refactor(Terminal):命令执行类支持各类npm包管理器

This commit is contained in:
妙码生花 2022-05-16 08:13:34 +08:00
parent ef273f82d0
commit c44e68d2b7
3 changed files with 129 additions and 55 deletions

View File

@ -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' => [
// 默认驱动方式

View File

@ -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');

View File

@ -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;
}
}