From c44e68d2b7ca16ebd8ff418edb25ffa7cff6442d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A6=99=E7=A0=81=E7=94=9F=E8=8A=B1?= <18523774412@qq.com> Date: Mon, 16 May 2022 08:13:34 +0800 Subject: [PATCH] =?UTF-8?q?refactor(Terminal):=E5=91=BD=E4=BB=A4=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E7=B1=BB=E6=94=AF=E6=8C=81=E5=90=84=E7=B1=BBnpm?= =?UTF-8?q?=E5=8C=85=E7=AE=A1=E7=90=86=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/buildadmin.php | 44 ++++++++++++++---- extend/ba/CommandExec.php | 95 +++++++++++++++++++++++++++++---------- extend/ba/Version.php | 45 +++++++++---------- 3 files changed, 129 insertions(+), 55 deletions(-) diff --git a/config/buildadmin.php b/config/buildadmin.php index 96c004f9..ab2a6dd1 100644 --- a/config/buildadmin.php +++ b/config/buildadmin.php @@ -16,15 +16,41 @@ return [ 'npm_package_manager' => 'cnpm', // 允许执行的命令 'allowed_commands' => [ - 'ping-baidu' => 'ping baidu.com', - 'cnpm-install' => 'cnpm install', - 'npm-v' => 'npm -v', - 'cnpm-v' => 'cnpm -v', - 'node-v' => 'node -v', - 'install-cnpm' => 'npm install -g cnpm --registry=https://registry.npmmirror.com', - 'test-install' => 'cd npm-install-test && cnpm install', - 'web-install' => 'cd ../web && cnpm install', - 'web-build' => 'cd ../web && cnpm run build:online', + 'install-package-manager' => [ + 'cnpm' => 'npm install cnpm -g --registry=https://registry.npmmirror.com', + 'yarn' => 'npm install -g yarn', + 'pnpm' => 'npm install -g pnpm', + 'ni' => 'npm install -g @antfu/ni', + ], + 'version-view' => [ + 'npm' => 'npm -v', + 'cnpm' => 'cnpm -v', + 'yarn' => 'yarn -v', + 'pnpm' => 'pnpm -v', + 'node' => 'node -v', + ], + 'test-install' => [ + 'npm' => 'cd npm-install-test && npm install', + 'cnpm' => 'cd npm-install-test && cnpm install', + 'yarn' => 'cd npm-install-test && yarn install', + 'pnpm' => 'cd npm-install-test && pnpm install', + 'ni' => 'cd npm-install-test && ni install', + ], + 'web-install' => [ + 'npm' => 'cd ../web && npm install', + 'cnpm' => 'cd ../web && cnpm install', + 'yarn' => 'cd ../web && yarn install', + 'pnpm' => 'cd ../web && pnpm install', + 'ni' => 'cd ../web && ni install', + ], + 'web-build' => [ + 'npm' => 'cd ../web && npm run build:online', + 'cnpm' => 'cd ../web && cnpm run build:online', + 'yarn' => 'cd ../web && yarn run build:online', + 'pnpm' => 'cd ../web && pnpm run build:online', + 'ni' => 'cd ../web && nr build:online', + ], + 'ping-baidu' => 'ping baidu.com', ], 'token' => [ // 默认驱动方式 diff --git a/extend/ba/CommandExec.php b/extend/ba/CommandExec.php index 1cee5c9d..217e58e0 100644 --- a/extend/ba/CommandExec.php +++ b/extend/ba/CommandExec.php @@ -60,6 +60,10 @@ class CommandExec */ protected $distDir = 'dist'; + /** + * 构造函数 + * @param bool $authentication 是否鉴权 + */ public function __construct($authentication) { set_time_limit(120); @@ -68,9 +72,7 @@ class CommandExec $auth = Auth::instance(); $auth->init($token); if (!$auth->isLogin()) { - $this->output('Error: Please login first'); - $this->outputFlag('exec-error'); - $this->break(); + $this->execError('Error: Please login first', true); } } $this->command = Config::get('buildadmin.allowed_commands'); @@ -91,21 +93,39 @@ class CommandExec /** * 获取命令 * @param string $key 命令key - * @param bool $outputError 是否直接输出错误 + * @param bool $outputError 是否直接输出错误(通过event-stream) * @return string */ protected function getCommand(string $key, bool $outputError = true): string { - if (!$key || !array_key_exists($key, $this->command)) { - if ($outputError) { - $this->output('Error: Command not allowed'); - $this->outputFlag('exec-error'); - } + if (!$key) { + if ($outputError) $this->execError('Error: Command not allowed', true); $this->break(); } $this->currentCommandKey = $key; - return $this->command[$key]; + + if (stripos($key, '.')) { + $key = explode('.', $key); + if (!array_key_exists($key[0], $this->command) || !is_array($this->command[$key[0]]) || !array_key_exists($key[1], $this->command[$key[0]])) { + if ($outputError) $this->execError('Error: Command not allowed', true); + $this->break(); + } + return $this->command[$key[0]][$key[1]]; + } else { + if (!array_key_exists($key, $this->command)) { + if ($outputError) $this->execError('Error: Command not allowed', true); + $this->break(); + } + return $this->command[$key]; + } + } + + public function execError($error, $break = false) + { + $this->output($error); + $this->outputFlag('exec-error'); + if ($break) $this->break(); } /** @@ -187,27 +207,56 @@ class CommandExec return $newStr; } + /** + * npm Install 时检测是否执行成功 + * @param string $output + */ + public function npmInstallCallback(string $output, $name) + { + if ($name == 'npm') { + $preg[] = "[added|removed|changed|audited] ([0-9]*) package"; + return preg_match('/' . implode('|', $preg) . '/i', $output); + } elseif ($name == 'cnpm') { + return strpos(strtolower($output), 'all packages installed') !== false; + } elseif ($name == 'pnpm') { + $preg = "/Progress: resolved ([0-9]*), reused ([0-9]*), downloaded ([0-9]*), added ([0-9]*), done/i"; + return preg_match($preg, $output); + } elseif ($name == 'yarn') { + return strpos(strtolower($output), 'Done in ') !== false; + } else { + return false; + } + } + /** * 输出检测,检测命令执行状态等操作 * @param $output */ public function outputCallback($output) { - if ($this->currentCommandKey == 'test-install' || $this->currentCommandKey == 'web-install') { - if (strpos(strtolower($output), 'all packages installed') !== false) { - $this->outputFlag('exec-success'); - } - } elseif ($this->currentCommandKey == 'install-cnpm') { - $preg = "/added ([0-9]*) packages in/i"; - $preg2 = "/added ([0-9]*) packages, removed/i"; - $preg3 = "/removed ([0-9]*) packages, and changed ([0-9]*) packages in/i"; - if (preg_match($preg, $output) || preg_match($preg2, $output) || preg_match($preg3, $output)) { - // 获取一次cnpm版本号 - if (Version::getCnpmVersion()) { + if (stripos($this->currentCommandKey, '.')) { + $commandKeyArr = explode('.', $this->currentCommandKey); + $commandPKey = $commandKeyArr[0] ?? ''; + } else { + $commandPKey = $this->currentCommandKey; + } + + if ($commandPKey == 'test-install' || $commandPKey == 'web-install') { + if (isset($commandKeyArr[1])) { + if ($commandKeyArr[1] == 'ni' && ($this->npmInstallCallback($output, 'npm') || $this->npmInstallCallback($output, 'cnpm') || $this->npmInstallCallback($output, 'pnpm') || $this->npmInstallCallback($output, 'yarn'))) { + $this->outputFlag('exec-success'); + } elseif ($this->npmInstallCallback($output, $commandKeyArr[1])) { $this->outputFlag('exec-success'); } } - } elseif ($this->currentCommandKey == 'web-build') { + } elseif ($commandPKey == 'install-package-manager') { + if ($this->npmInstallCallback($output, 'npm')) { + // 获取一次版本号 + if (isset($commandKeyArr[1]) && in_array($commandKeyArr[1], ['cnpm', 'yarn', 'pnpm']) && Version::getVersion($commandKeyArr[1])) { + $this->outputFlag('exec-success'); + } + } + } elseif ($commandPKey == 'web-build') { if (strpos(strtolower($output), 'build successfully!') !== false) { if ($this->mvDist()) { $this->outputFlag('exec-success'); @@ -215,7 +264,7 @@ class CommandExec $this->output('Build succeeded, but move file failed. Please operate manually.'); } } - } elseif ($this->currentCommandKey == 'npm-v') { + } elseif ($this->currentCommandKey == 'version-view.npm') { $preg = "/([0-9]+)\.([0-9]+)\.([0-9]+)/"; if (preg_match($preg, $output)) { $this->outputFlag('exec-success'); diff --git a/extend/ba/Version.php b/extend/ba/Version.php index c19d9609..18ae9bee 100644 --- a/extend/ba/Version.php +++ b/extend/ba/Version.php @@ -78,25 +78,9 @@ class Version return false; } - public static function getNpmVersion() - { - $execOut = CommandExec::instance(false)->getOutputFromPopen('npm-v'); - if ($execOut) { - if (isset($execOut[0]) && self::checkDigitalVersion($execOut[0])) { - return $execOut[0]; - } else if (isset($execOut[1]) && self::checkDigitalVersion($execOut[1])) { - return $execOut[1]; - } else { - return false; - } - } else { - return false; - } - } - public static function getCnpmVersion() { - $execOut = CommandExec::instance(false)->getOutputFromPopen('cnpm-v'); + $execOut = CommandExec::instance(false)->getOutputFromPopen('version-view.cnpm'); if ($execOut) { $execOut = implode('', $execOut); $preg = '/cnpm@(.+?) \(/is'; @@ -107,13 +91,28 @@ class Version } } - public static function getNodeJsVersion() + /** + * 获取依赖版本号 + * @param string $name 支持:npm、cnpm、yarn、pnpm、node + */ + public static function getVersion(string $name) { - $execOut = CommandExec::instance(false)->getOutputFromPopen('node-v'); - if ($execOut && isset($execOut[0]) && self::checkDigitalVersion($execOut[0])) { - return $execOut[0]; - } else { - return false; + if ($name == 'cnpm') { + return self::getCnpmVersion(); + } elseif (in_array($name, ['npm', 'yarn', 'pnpm', 'node'])) { + $execOut = CommandExec::instance(false)->getOutputFromPopen('version-view.' . $name); + if ($execOut) { + // 检测两行,第一行可能会是个警告消息 + for ($i = 0; $i < 2; $i++) { + if (isset($execOut[$i]) && self::checkDigitalVersion($execOut[$i])) { + return $execOut[$i]; + } + } + } else { + return false; + } } + + return false; } } \ No newline at end of file