From a430cf59c407c9a46e06c70006eee717ea71e4cd Mon Sep 17 00:00:00 2001 From: sunxyw Date: Fri, 16 Dec 2022 21:58:19 +0800 Subject: [PATCH] add docker init to InitCommand --- docker/walle-q/Dockerfile | 12 ++-- src/Globals/global_defines_app.php | 5 +- src/ZM/Command/InitCommand.php | 106 +++++++++++++++++++++++------ 3 files changed, 96 insertions(+), 27 deletions(-) diff --git a/docker/walle-q/Dockerfile b/docker/walle-q/Dockerfile index 1a69aab8..2d784d2f 100644 --- a/docker/walle-q/Dockerfile +++ b/docker/walle-q/Dockerfile @@ -2,11 +2,13 @@ FROM alpine:latest MAINTAINER sunxyw -RUN apk add --no-cache curl && \ - mkdir -p /bot && \ - curl -L -o /bot/walle-q https://github.com/onebot-walle/walle-q/releases/latest/download/walle-q-i686-linux-musl && \ - chmod +x /bot/walle-q +RUN apk add --no-cache curl +RUN mkdir -p /bot && \ + curl -fsSL https://github.com/onebot-walle/walle-q/releases/latest/download/walle-q-i686-linux-musl.tar.gz -O && \ + tar -zxvf walle-q-i686-linux-musl.tar.gz -C /bot && \ + rm -rf walle-q-i686-linux-musl.tar.gz && \ + chmod +x /bot/walle-q-i686-linux-musl ENV TZ=Asia/Shanghai -ENTRYPOINT [ "/bot/walle-q" ] +ENTRYPOINT [ "/bot/walle-q-i686-linux-musl" ] diff --git a/src/Globals/global_defines_app.php b/src/Globals/global_defines_app.php index e2af9fa4..ed798513 100644 --- a/src/Globals/global_defines_app.php +++ b/src/Globals/global_defines_app.php @@ -31,6 +31,9 @@ const ZM_ERR_METHOD_NOT_FOUND = 1; // 找不到方法 const ZM_ERR_ROUTE_NOT_FOUND = 2; // 找不到路由 const ZM_ERR_ROUTE_METHOD_NOT_ALLOWED = 3; // 路由方法不允许 +const LOAD_MODE_VENDOR = 0; // 从 vendor 加载 +const LOAD_MODE_SRC = 1; // 从 src 加载 + /* 定义工作目录 */ define('WORKING_DIR', getcwd()); @@ -48,7 +51,7 @@ if (DIRECTORY_SEPARATOR === '\\') { } /* 定义启动模式,这里指的是框架本身的源码目录是通过 composer 加入 vendor 加载的还是直接放到 src 目录加载的,前者为 1,后者为 0 */ -define('LOAD_MODE', is_dir(zm_dir(SOURCE_ROOT_DIR . '/src/ZM')) ? 0 : 1); +define('LOAD_MODE', is_dir(zm_dir(SOURCE_ROOT_DIR . '/src/ZM')) ? LOAD_MODE_VENDOR : LOAD_MODE_SRC); /* 定义框架本身所处的根目录,此处如果 LOAD_MODE 为 1 的话,框架自身的根目录在 vendor/zhamao/framework 子目录下 */ if (Phar::running() !== '') { diff --git a/src/ZM/Command/InitCommand.php b/src/ZM/Command/InitCommand.php index 7ca65cdc..e4ac59ab 100644 --- a/src/ZM/Command/InitCommand.php +++ b/src/ZM/Command/InitCommand.php @@ -6,6 +6,7 @@ namespace ZM\Command; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\ConsoleSectionOutput; +use Symfony\Component\Console\Output\OutputInterface; use ZM\Exception\InitException; class InitCommand extends Command @@ -19,9 +20,10 @@ class InitCommand extends Command protected function configure(): void { - $this->setDescription('Initialize framework starter | 初始化框架运行的基础文件'); + $this->setDescription('初始化框架运行的基础文件'); $this->setDefinition([ - new InputOption('force', 'F', null, '强制重制,覆盖现有文件'), + new InputOption('force', 'f', InputOption::VALUE_NONE, '覆盖现有文件'), + new InputOption('docker', null, InputOption::VALUE_NONE, '启用 Docker 支持'), ]); $this->setHelp('提取框架的基础文件到当前目录,以便于快速开始开发。'); } @@ -32,25 +34,10 @@ class InitCommand extends Command $this->force = $this->input->getOption('force'); $this->section('提取框架基础文件', function (ConsoleSectionOutput $section) { - foreach ($this->getExtractFiles() as $file) { - $section->write("提取 {$file} ... "); - if ($this->shouldExtractFile($file)) { - try { - $this->extractFile($file); - $section->write('完成'); - } catch (InitException $e) { - $section->write('失败'); - throw $e; - } finally { - $section->writeln(''); - } - } else { - $section->writeln('跳过(已存在)'); - } - } + $this->extractFiles($this->getExtractFiles(), $section); }); - if (LOAD_MODE === 1) { + if (LOAD_MODE === LOAD_MODE_SRC) { $this->section('应用自动加载配置', function (ConsoleSectionOutput $section) { $autoload = [ 'psr-4' => [ @@ -62,6 +49,8 @@ class InitCommand extends Command ], ]; + $section->write('更新 composer.json ... '); + if (!file_exists($this->base_path . '/composer.json')) { throw new InitException('未找到 composer.json 文件', '请检查当前目录是否为项目根目录', 41); } @@ -84,13 +73,39 @@ class InitCommand extends Command throw new InitException('写入 composer.json 文件失败', '', 0, $e); } - $section->writeln('执行 composer dump-autoload ...'); + $section->writeln('完成'); + + $section->write('执行 composer dump-autoload ... '); exec('composer dump-autoload'); $section->writeln('完成'); }); } + if ($this->input->getOption('docker')) { + $this->section('应用 Docker 支持', function (ConsoleSectionOutput $section) { + $files = $this->getFilesFromPatterns([ + '/docker/*/Dockerfile', + '/docker/environment.env.example', + '/docker-compose.yml', + ]); + $this->extractFiles($files, $section); + + // 生成 env 文件 + if ($this->shouldExtractFile('/docker/environment.env')) { + $section->write('生成环境变量文件 ... '); + $env = file_get_contents($this->base_path . '/docker/environment.env.example'); + foreach ($this->getEnvVariables() as $key => $value) { + $env = $this->injectEnv($env, $key, $value); + } + file_put_contents($this->base_path . '/docker/environment.env', $env); + $section->writeln('完成'); + } else { + $section->writeln('生成环境变量文件 ... 跳过(已存在)'); + } + }); + } + // 将命令行入口标记为可执行 chmod($this->base_path . '/zhamao', 0755); return 0; @@ -105,10 +120,15 @@ class InitCommand extends Command '/src/Globals/*.php', ]; + return $this->getFilesFromPatterns($patterns); + } + + private function getFilesFromPatterns(array $patterns): array + { $files = []; foreach ($patterns as $pattern) { // TODO: 优化代码,避免在循环中使用 array_merge 以减少资源消耗 - $files = array_merge($files, glob($this->getVendorPath($pattern))); + $files = array_merge($files, glob($this->getVendorPath($pattern), GLOB_BRACE)); } return array_map(function ($file) { return str_replace($this->getVendorPath(''), '', $file); @@ -173,4 +193,48 @@ class InitCommand extends Command } return $this->base_path . '/vendor/' . $package_name . $file; } + + private function extractFiles(array $files, OutputInterface $output): void + { + foreach ($files as $file) { + $output->write("提取 {$file} ... "); + if ($this->shouldExtractFile($file)) { + try { + $this->extractFile($file); + $output->write('完成'); + } catch (InitException $e) { + $output->write('失败'); + throw $e; + } finally { + $output->writeln(''); + } + } else { + $output->writeln('跳过(已存在)'); + } + } + } + + private function injectEnv(string $env, string $key, string $value): string + { + $pattern = "/^{$key}=.+$/m"; + if (preg_match($pattern, $env)) { + return preg_replace($pattern, "{$key}={$value}", $env); + } + + return $env . PHP_EOL . "{$key}={$value}"; + } + + private function getEnvVariables(): array + { + return [ + 'REDIS_PASSWORD' => bin2hex(random_bytes(8)), + + 'POSTGRES_USER' => 'root', + 'POSTGRES_PASSWORD' => bin2hex(random_bytes(8)), + + 'POSTGRES_APPLICATION_DATABASE' => 'zhamao', + 'POSTGRES_APPLICATION_USER' => 'zhamao', + 'POSTGRES_APPLICATION_USER_PASSWORD' => bin2hex(random_bytes(8)), + ]; + } }