Files
dafuweng-buildadmin/dafuweng-webman/app/admin/library/module/Manage.php
2026-03-07 19:42:22 +08:00

901 lines
32 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace app\admin\library\module;
use Throwable;
use ba\Version;
use ba\Depends;
use ba\Exception;
use ba\Filesystem;
use FilesystemIterator;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use Webman\Http\Request;
/**
* 模块管理类Webman 迁移版)
*/
class Manage
{
public const UNINSTALLED = 0;
public const INSTALLED = 1;
public const WAIT_INSTALL = 2;
public const CONFLICT_PENDING = 3;
public const DEPENDENT_WAIT_INSTALL = 4;
public const DIRECTORY_OCCUPIED = 5;
public const DISABLE = 6;
protected static ?Manage $instance = null;
protected string $installDir;
protected string $backupsDir;
protected string $uid;
protected string $modulesDir;
public static function instance(string $uid = ''): Manage
{
if (self::$instance === null) {
self::$instance = new static($uid);
}
return self::$instance->setModuleUid($uid);
}
public function __construct(string $uid)
{
$this->installDir = root_path() . 'modules' . DIRECTORY_SEPARATOR;
$this->backupsDir = $this->installDir . 'backups' . DIRECTORY_SEPARATOR;
if (!is_dir($this->installDir)) {
mkdir($this->installDir, 0755, true);
}
if (!is_dir($this->backupsDir)) {
mkdir($this->backupsDir, 0755, true);
}
if ($uid) {
$this->setModuleUid($uid);
} else {
$this->uid = '';
$this->modulesDir = $this->installDir;
}
}
public function getInstallState(): int
{
if (!is_dir($this->modulesDir)) {
return self::UNINSTALLED;
}
$info = $this->getInfo();
if ($info && isset($info['state'])) {
return $info['state'];
}
return Filesystem::dirIsEmpty($this->modulesDir) ? self::UNINSTALLED : self::DIRECTORY_OCCUPIED;
}
/**
* 从 Webman Request 上传安装(适配 Multipart 上传)
* @return array 模块基本信息
* @throws Throwable
*/
public static function uploadFromRequest(Request $request): array
{
$file = $request->file('file');
if (!$file) {
throw new Exception('Parameter error');
}
$token = $request->post('token', $request->get('token', ''));
if (!$token) {
throw new Exception('Please login to the official website account first');
}
$uploadDir = root_path() . 'public' . DIRECTORY_SEPARATOR . 'storage' . DIRECTORY_SEPARATOR . 'upload' . DIRECTORY_SEPARATOR;
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
$saveName = 'temp' . DIRECTORY_SEPARATOR . date('YmdHis') . '_' . ($file->getUploadName() ?? 'module.zip');
$savePath = $uploadDir . $saveName;
$saveDir = dirname($savePath);
if (!is_dir($saveDir)) {
mkdir($saveDir, 0755, true);
}
$file->move($savePath);
$relativePath = 'storage/upload/' . str_replace(DIRECTORY_SEPARATOR, '/', $saveName);
try {
return self::instance('')->doUpload($token, $relativePath);
} finally {
if (is_file($savePath)) {
@unlink($savePath);
}
}
}
/**
* 下载模块文件
* @throws Throwable
*/
public function download(): string
{
$req = function_exists('request') ? request() : null;
$token = $req ? ($req->post('token', $req->get('token', ''))) : '';
$version = $req ? ($req->post('version', $req->get('version', ''))) : '';
$orderId = $req ? ($req->post('orderId', $req->get('orderId', 0))) : 0;
if (!$orderId) {
throw new Exception('Order not found');
}
$zipFile = Server::download($this->uid, $this->installDir, [
'version' => $version,
'orderId' => $orderId,
'nuxtVersion' => Server::getNuxtVersion(),
'sysVersion' => config('buildadmin.version', ''),
'installed' => Server::getInstalledIds($this->installDir),
'ba-user-token' => $token,
]);
Filesystem::delDir($this->modulesDir);
Filesystem::unzip($zipFile);
@unlink($zipFile);
$this->checkPackage();
$this->setInfo([
'state' => self::WAIT_INSTALL,
]);
return $zipFile;
}
/**
* 上传安装token + 文件相对路径)
* @throws Throwable
*/
public function doUpload(string $token, string $file): array
{
$file = Filesystem::fsFit(root_path() . 'public' . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $file));
if (!is_file($file)) {
throw new Exception('Zip file not found');
}
$copyTo = $this->installDir . 'uploadTemp' . date('YmdHis') . '.zip';
copy($file, $copyTo);
$copyToDir = Filesystem::unzip($copyTo);
$copyToDir .= DIRECTORY_SEPARATOR;
@unlink($file);
@unlink($copyTo);
$info = Server::getIni($copyToDir);
if (empty($info['uid'])) {
Filesystem::delDir($copyToDir);
throw new Exception('Basic configuration of the Module is incomplete');
}
$this->setModuleUid($info['uid']);
$upgrade = false;
if (is_dir($this->modulesDir)) {
$oldInfo = $this->getInfo();
if ($oldInfo && !empty($oldInfo['uid'])) {
$versions = explode('.', $oldInfo['version'] ?? '0.0.0');
if (isset($versions[2])) {
$versions[2]++;
}
$nextVersion = implode('.', $versions);
$upgrade = Version::compare($nextVersion, $info['version'] ?? '');
if ($upgrade) {
if (!in_array($oldInfo['state'], [self::UNINSTALLED, self::WAIT_INSTALL, self::DISABLE])) {
Filesystem::delDir($copyToDir);
throw new Exception('Please disable the module before updating');
}
} else {
Filesystem::delDir($copyToDir);
throw new Exception('Module already exists');
}
}
if (!Filesystem::dirIsEmpty($this->modulesDir) && !$upgrade) {
Filesystem::delDir($copyToDir);
throw new Exception('The directory required by the module is occupied');
}
}
try {
Server::installPreCheck([
'uid' => $info['uid'],
'version' => $info['version'] ?? '',
'sysVersion' => config('buildadmin.version', ''),
'nuxtVersion' => Server::getNuxtVersion(),
'moduleVersion' => $info['version'] ?? '',
'ba-user-token' => $token,
'installed' => Server::getInstalledIds($this->installDir),
'server' => 1,
]);
} catch (Throwable $e) {
Filesystem::delDir($copyToDir);
throw $e;
}
$newInfo = ['state' => self::WAIT_INSTALL];
if ($upgrade) {
$info['update'] = 1;
Filesystem::delDir($this->modulesDir);
}
rename($copyToDir, $this->modulesDir);
$this->checkPackage();
$this->setInfo($newInfo);
return $info;
}
/**
* 安装模块
* @throws Throwable
*/
public function install(bool $update): array
{
$state = $this->getInstallState();
if ($update) {
if (!in_array($state, [self::UNINSTALLED, self::WAIT_INSTALL, self::DISABLE])) {
throw new Exception('Please disable the module before updating');
}
if ($state == self::UNINSTALLED || $state != self::WAIT_INSTALL) {
$this->download();
}
} else {
if ($state == self::INSTALLED || $state == self::DIRECTORY_OCCUPIED || $state == self::DISABLE) {
throw new Exception('Module already exists');
}
if ($state == self::UNINSTALLED) {
$this->download();
}
}
Server::importSql($this->modulesDir);
$info = $this->getInfo();
if ($update) {
$info['update'] = 1;
Server::execEvent($this->uid, 'update');
}
$req = function_exists('request') ? request() : null;
$extend = $req ? ($req->post('extend') ?? []) : [];
if (!isset($extend['conflictHandle'])) {
Server::execEvent($this->uid, 'install');
}
$this->enable('install');
return $info;
}
/**
* 卸载
* @throws Throwable
*/
public function uninstall(): void
{
$info = $this->getInfo();
if (($info['state'] ?? 0) != self::DISABLE) {
throw new Exception('Please disable the module first', 0, [
'uid' => $this->uid,
]);
}
Server::execEvent($this->uid, 'uninstall');
Filesystem::delDir($this->modulesDir);
}
/**
* 修改模块状态
* @throws Throwable
*/
public function changeState(bool $state): array
{
$info = $this->getInfo();
if (!$state) {
$canDisable = [
self::INSTALLED,
self::CONFLICT_PENDING,
self::DEPENDENT_WAIT_INSTALL,
];
if (!in_array($info['state'] ?? 0, $canDisable)) {
throw new Exception('The current state of the module cannot be set to disabled', 0, [
'uid' => $this->uid,
'state' => $info['state'] ?? 0,
]);
}
return $this->disable();
}
if (($info['state'] ?? 0) != self::DISABLE) {
throw new Exception('The current state of the module cannot be set to enabled', 0, [
'uid' => $this->uid,
'state' => $info['state'] ?? 0,
]);
}
$this->setInfo([
'state' => self::WAIT_INSTALL,
]);
return $info;
}
/**
* 启用
* @throws Throwable
*/
public function enable(string $trigger): void
{
Server::installWebBootstrap($this->uid, $this->modulesDir);
Server::createRuntime($this->modulesDir);
$this->conflictHandle($trigger);
Server::execEvent($this->uid, 'enable');
$this->dependUpdateHandle();
}
/**
* 禁用
* @throws Throwable
*/
public function disable(): array
{
$req = function_exists('request') ? request() : null;
$update = $req ? filter_var($req->post('update', false), FILTER_VALIDATE_BOOLEAN) : false;
$confirmConflict = $req ? filter_var($req->post('confirmConflict', false), FILTER_VALIDATE_BOOLEAN) : false;
$dependConflictSolution = $req ? ($req->post('dependConflictSolution') ?? []) : [];
$info = $this->getInfo();
$zipFile = $this->backupsDir . $this->uid . '-install.zip';
$zipDir = false;
if (is_file($zipFile)) {
try {
$zipDir = $this->backupsDir . $this->uid . '-install' . DIRECTORY_SEPARATOR;
Filesystem::unzip($zipFile, $zipDir);
} catch (Exception) {
// skip
}
}
$conflictFile = Server::getFileList($this->modulesDir, true);
$dependConflict = $this->disableDependCheck();
if (($conflictFile || !self::isEmptyArray($dependConflict)) && !$confirmConflict) {
$dependConflictTemp = [];
foreach ($dependConflict as $env => $item) {
foreach ($item as $depend => $v) {
$dependConflictTemp[] = [
'env' => $env,
'depend' => $depend,
'dependTitle' => $depend . ' ' . $v,
'solution' => 'delete',
];
}
}
throw new Exception('Module file updated', -1, [
'uid' => $this->uid,
'conflictFile' => $conflictFile,
'dependConflict' => $dependConflictTemp,
]);
}
Server::execEvent($this->uid, 'disable', ['update' => $update]);
$delNpmDepend = false;
$delNuxtNpmDepend = false;
$delComposerDepend = false;
foreach ($dependConflictSolution as $env => $depends) {
if (!$depends) continue;
if ($env == 'require' || $env == 'require-dev') {
$delComposerDepend = true;
} elseif ($env == 'dependencies' || $env == 'devDependencies') {
$delNpmDepend = true;
} elseif ($env == 'nuxtDependencies' || $env == 'nuxtDevDependencies') {
$delNuxtNpmDepend = true;
}
}
$dependJsonFiles = [
'composer' => 'composer.json',
'webPackage' => 'web' . DIRECTORY_SEPARATOR . 'package.json',
'webNuxtPackage' => 'web-nuxt' . DIRECTORY_SEPARATOR . 'package.json',
];
$dependWaitInstall = [];
if ($delComposerDepend) {
$conflictFile[] = $dependJsonFiles['composer'];
$dependWaitInstall[] = [
'pm' => false,
'command' => 'composer.update',
'type' => 'composer_dependent_wait_install',
];
}
if ($delNpmDepend) {
$conflictFile[] = $dependJsonFiles['webPackage'];
$dependWaitInstall[] = [
'pm' => true,
'command' => 'web-install',
'type' => 'npm_dependent_wait_install',
];
}
if ($delNuxtNpmDepend) {
$conflictFile[] = $dependJsonFiles['webNuxtPackage'];
$dependWaitInstall[] = [
'pm' => true,
'command' => 'nuxt-install',
'type' => 'nuxt_npm_dependent_wait_install',
];
}
if ($conflictFile) {
$overwriteDir = Server::getOverwriteDir();
foreach ($conflictFile as $key => $item) {
$paths = explode(DIRECTORY_SEPARATOR, $item);
if (in_array($paths[0], $overwriteDir) || in_array($item, $dependJsonFiles)) {
$conflictFile[$key] = $item;
} else {
$conflictFile[$key] = Filesystem::fsFit(str_replace(root_path(), '', $this->modulesDir . $item));
}
if (!is_file(root_path() . $conflictFile[$key])) {
unset($conflictFile[$key]);
}
}
$backupsZip = $this->backupsDir . $this->uid . '-disable-' . date('YmdHis') . '.zip';
Filesystem::zip($conflictFile, $backupsZip);
}
$serverDepend = new Depends(root_path() . 'composer.json', 'composer');
$webDep = new Depends(root_path() . 'web' . DIRECTORY_SEPARATOR . 'package.json');
$webNuxtDep = new Depends(root_path() . 'web-nuxt' . DIRECTORY_SEPARATOR . 'package.json');
foreach ($dependConflictSolution as $env => $depends) {
if (!$depends) continue;
$dev = stripos($env, 'dev') !== false;
if ($env == 'require' || $env == 'require-dev') {
$serverDepend->removeDepends($depends, $dev);
} elseif ($env == 'dependencies' || $env == 'devDependencies') {
$webDep->removeDepends($depends, $dev);
} elseif ($env == 'nuxtDependencies' || $env == 'nuxtDevDependencies') {
$webNuxtDep->removeDepends($depends, $dev);
}
}
$composerConfig = Server::getConfig($this->modulesDir, 'composerConfig');
if ($composerConfig) {
$serverDepend->removeComposerConfig($composerConfig);
}
$protectedFiles = Server::getConfig($this->modulesDir, 'protectedFiles');
foreach ($protectedFiles as &$protectedFile) {
$protectedFile = Filesystem::fsFit(root_path() . $protectedFile);
}
$moduleFile = Server::getFileList($this->modulesDir);
foreach ($moduleFile as &$file) {
$moduleFilePath = Filesystem::fsFit($this->modulesDir . $file);
$file = Filesystem::fsFit(root_path() . $file);
if (!file_exists($file)) continue;
if (!file_exists($moduleFilePath)) {
if (!is_dir(dirname($moduleFilePath))) {
mkdir(dirname($moduleFilePath), 0755, true);
}
copy($file, $moduleFilePath);
}
if (in_array($file, $protectedFiles)) {
continue;
}
if (file_exists($file)) {
unlink($file);
}
Filesystem::delEmptyDir(dirname($file));
}
if ($zipDir) {
$unrecoverableFiles = [
Filesystem::fsFit(root_path() . 'composer.json'),
Filesystem::fsFit(root_path() . 'web/package.json'),
Filesystem::fsFit(root_path() . 'web-nuxt/package.json'),
];
foreach (
new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($zipDir, FilesystemIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
) as $item
) {
$backupsFile = Filesystem::fsFit(root_path() . str_replace($zipDir, '', $item->getPathname()));
if (in_array($backupsFile, $moduleFile) && !in_array($backupsFile, $protectedFiles)) {
continue;
}
if ($item->isDir()) {
if (!is_dir($backupsFile)) {
mkdir($backupsFile, 0755, true);
}
} elseif (!in_array($backupsFile, $unrecoverableFiles)) {
copy($item->getPathname(), $backupsFile);
}
}
}
if ($zipDir && is_dir($zipDir)) {
Filesystem::delDir($zipDir);
}
Server::uninstallWebBootstrap($this->uid);
$this->setInfo([
'state' => self::DISABLE,
]);
if ($update) {
throw new Exception('update', -3, [
'uid' => $this->uid,
]);
}
if (!empty($dependWaitInstall)) {
throw new Exception('dependent wait install', -2, [
'uid' => $this->uid,
'wait_install' => $dependWaitInstall,
]);
}
return $info;
}
/**
* 处理依赖和文件冲突
* @throws Throwable
*/
public function conflictHandle(string $trigger): bool
{
$info = $this->getInfo();
if (!in_array($info['state'] ?? 0, [self::WAIT_INSTALL, self::CONFLICT_PENDING])) {
return false;
}
$fileConflict = Server::getFileList($this->modulesDir, true);
$dependConflict = Server::dependConflictCheck($this->modulesDir);
$installFiles = Server::getFileList($this->modulesDir);
$depends = Server::getDepend($this->modulesDir);
$coverFiles = [];
$discardFiles = [];
$serverDep = new Depends(root_path() . 'composer.json', 'composer');
$webDep = new Depends(root_path() . 'web' . DIRECTORY_SEPARATOR . 'package.json');
$webNuxtDep = new Depends(root_path() . 'web-nuxt' . DIRECTORY_SEPARATOR . 'package.json');
$req = function_exists('request') ? request() : null;
$extend = $req ? ($req->post('extend') ?? []) : [];
if ($fileConflict || !self::isEmptyArray($dependConflict)) {
if (!$extend) {
$fileConflictTemp = [];
foreach ($fileConflict as $key => $item) {
$fileConflictTemp[$key] = [
'newFile' => $this->uid . DIRECTORY_SEPARATOR . $item,
'oldFile' => $item,
'solution' => 'cover',
];
}
$dependConflictTemp = [];
foreach ($dependConflict as $env => $item) {
$dev = stripos($env, 'dev') !== false;
foreach ($item as $depend => $v) {
$oldDepend = '';
if (in_array($env, ['require', 'require-dev'])) {
$oldDepend = $depend . ' ' . $serverDep->hasDepend($depend, $dev);
} elseif (in_array($env, ['dependencies', 'devDependencies'])) {
$oldDepend = $depend . ' ' . $webDep->hasDepend($depend, $dev);
} elseif (in_array($env, ['nuxtDependencies', 'nuxtDevDependencies'])) {
$oldDepend = $depend . ' ' . $webNuxtDep->hasDepend($depend, $dev);
}
$dependConflictTemp[] = [
'env' => $env,
'newDepend' => $depend . ' ' . $v,
'oldDepend' => $oldDepend,
'depend' => $depend,
'solution' => 'cover',
];
}
}
$this->setInfo([
'state' => self::CONFLICT_PENDING,
]);
throw new Exception('Module file conflicts', -1, [
'fileConflict' => $fileConflictTemp,
'dependConflict' => $dependConflictTemp,
'uid' => $this->uid,
'state' => self::CONFLICT_PENDING,
]);
}
if ($fileConflict && isset($extend['fileConflict'])) {
foreach ($installFiles as $ikey => $installFile) {
if (isset($extend['fileConflict'][$installFile])) {
if ($extend['fileConflict'][$installFile] == 'discard') {
$discardFiles[] = $installFile;
unset($installFiles[$ikey]);
} else {
$coverFiles[] = $installFile;
}
}
}
}
if (!self::isEmptyArray($dependConflict) && isset($extend['dependConflict'])) {
foreach ($depends as $fKey => $fItem) {
foreach ($fItem as $cKey => $cItem) {
if (isset($extend['dependConflict'][$fKey][$cKey])) {
if ($extend['dependConflict'][$fKey][$cKey] == 'discard') {
unset($depends[$fKey][$cKey]);
}
}
}
}
}
}
if ($depends) {
foreach ($depends as $key => $item) {
if (!$item) continue;
if ($key == 'require' || $key == 'require-dev') {
$coverFiles[] = 'composer.json';
continue;
}
if ($key == 'dependencies' || $key == 'devDependencies') {
$coverFiles[] = 'web' . DIRECTORY_SEPARATOR . 'package.json';
}
if ($key == 'nuxtDependencies' || $key == 'nuxtDevDependencies') {
$coverFiles[] = 'web-nuxt' . DIRECTORY_SEPARATOR . 'package.json';
}
}
}
if ($coverFiles) {
$backupsZip = $trigger == 'install' ? $this->backupsDir . $this->uid . '-install.zip' : $this->backupsDir . $this->uid . '-cover-' . date('YmdHis') . '.zip';
Filesystem::zip($coverFiles, $backupsZip);
}
if ($depends) {
$npm = false;
$composer = false;
$nuxtNpm = false;
$composerConfig = Server::getConfig($this->modulesDir, 'composerConfig');
if ($composerConfig) {
$serverDep->setComposerConfig($composerConfig);
}
foreach ($depends as $key => $item) {
if (!$item) continue;
if ($key == 'require') {
$composer = true;
$serverDep->addDepends($item, false, true);
} elseif ($key == 'require-dev') {
$composer = true;
$serverDep->addDepends($item, true, true);
} elseif ($key == 'dependencies') {
$npm = true;
$webDep->addDepends($item, false, true);
} elseif ($key == 'devDependencies') {
$npm = true;
$webDep->addDepends($item, true, true);
} elseif ($key == 'nuxtDependencies') {
$nuxtNpm = true;
$webNuxtDep->addDepends($item, false, true);
} elseif ($key == 'nuxtDevDependencies') {
$nuxtNpm = true;
$webNuxtDep->addDepends($item, true, true);
}
}
if ($npm) {
$info['npm_dependent_wait_install'] = 1;
$info['state'] = self::DEPENDENT_WAIT_INSTALL;
}
if ($composer) {
$info['composer_dependent_wait_install'] = 1;
$info['state'] = self::DEPENDENT_WAIT_INSTALL;
}
if ($nuxtNpm) {
$info['nuxt_npm_dependent_wait_install'] = 1;
$info['state'] = self::DEPENDENT_WAIT_INSTALL;
}
$info = $info ?? $this->getInfo();
if (($info['state'] ?? 0) != self::DEPENDENT_WAIT_INSTALL) {
$this->setInfo(['state' => self::INSTALLED]);
} else {
$this->setInfo([], $info);
}
} else {
$this->setInfo(['state' => self::INSTALLED]);
}
$overwriteDir = Server::getOverwriteDir();
foreach ($overwriteDir as $dirItem) {
$baseDir = $this->modulesDir . $dirItem;
$destDir = root_path() . $dirItem;
if (!is_dir($baseDir)) continue;
foreach (
new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($baseDir, FilesystemIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
) as $item
) {
$destDirItem = Filesystem::fsFit($destDir . DIRECTORY_SEPARATOR . str_replace($baseDir, '', $item->getPathname()));
if ($item->isDir()) {
Filesystem::mkdir($destDirItem);
} elseif (!in_array(str_replace(root_path(), '', $destDirItem), $discardFiles)) {
Filesystem::mkdir(dirname($destDirItem));
copy($item->getPathname(), $destDirItem);
}
}
if (config('buildadmin.module_pure_install', false)) {
Filesystem::delDir($baseDir);
}
}
return true;
}
/**
* 依赖升级处理
* @throws Throwable
*/
public function dependUpdateHandle(): void
{
$info = $this->getInfo();
if (($info['state'] ?? 0) == self::DEPENDENT_WAIT_INSTALL) {
$waitInstall = [];
if (isset($info['composer_dependent_wait_install'])) {
$waitInstall[] = 'composer_dependent_wait_install';
}
if (isset($info['npm_dependent_wait_install'])) {
$waitInstall[] = 'npm_dependent_wait_install';
}
if (isset($info['nuxt_npm_dependent_wait_install'])) {
$waitInstall[] = 'nuxt_npm_dependent_wait_install';
}
if ($waitInstall) {
throw new Exception('dependent wait install', -2, [
'uid' => $this->uid,
'state' => self::DEPENDENT_WAIT_INSTALL,
'wait_install' => $waitInstall,
]);
} else {
$this->setInfo(['state' => self::INSTALLED]);
}
}
}
/**
* 依赖安装完成标记
* @throws Throwable
*/
public function dependentInstallComplete(string $type): void
{
$info = $this->getInfo();
if (($info['state'] ?? 0) == self::DEPENDENT_WAIT_INSTALL) {
if ($type == 'npm') {
unset($info['npm_dependent_wait_install']);
}
if ($type == 'nuxt_npm') {
unset($info['nuxt_npm_dependent_wait_install']);
}
if ($type == 'composer') {
unset($info['composer_dependent_wait_install']);
}
if ($type == 'all') {
unset($info['npm_dependent_wait_install'], $info['composer_dependent_wait_install'], $info['nuxt_npm_dependent_wait_install']);
}
if (!isset($info['npm_dependent_wait_install']) && !isset($info['composer_dependent_wait_install']) && !isset($info['nuxt_npm_dependent_wait_install'])) {
$info['state'] = self::INSTALLED;
}
$this->setInfo([], $info);
}
}
public function disableDependCheck(): array
{
$depend = Server::getDepend($this->modulesDir);
if (!$depend) return [];
$serverDep = new Depends(root_path() . 'composer.json', 'composer');
$webDep = new Depends(root_path() . 'web' . DIRECTORY_SEPARATOR . 'package.json');
$webNuxtDep = new Depends(root_path() . 'web-nuxt' . DIRECTORY_SEPARATOR . 'package.json');
foreach ($depend as $key => $depends) {
$dev = stripos($key, 'dev') !== false;
if ($key == 'require' || $key == 'require-dev') {
foreach ($depends as $dependKey => $dependItem) {
if (!$serverDep->hasDepend($dependKey, $dev)) {
unset($depends[$dependKey]);
}
}
$depend[$key] = $depends;
} elseif ($key == 'dependencies' || $key == 'devDependencies') {
foreach ($depends as $dependKey => $dependItem) {
if (!$webDep->hasDepend($dependKey, $dev)) {
unset($depends[$dependKey]);
}
}
$depend[$key] = $depends;
} elseif ($key == 'nuxtDependencies' || $key == 'nuxtDevDependencies') {
foreach ($depends as $dependKey => $dependItem) {
if (!$webNuxtDep->hasDepend($dependKey, $dev)) {
unset($depends[$dependKey]);
}
}
$depend[$key] = $depends;
}
}
return $depend;
}
/**
* 检查包是否完整
* @throws Throwable
*/
public function checkPackage(): bool
{
if (!is_dir($this->modulesDir)) {
throw new Exception('Module package file does not exist');
}
$info = $this->getInfo();
$infoKeys = ['uid', 'title', 'intro', 'author', 'version', 'state'];
foreach ($infoKeys as $value) {
if (!array_key_exists($value, $info)) {
Filesystem::delDir($this->modulesDir);
throw new Exception('Basic configuration of the Module is incomplete');
}
}
return true;
}
public function getInfo(): array
{
return Server::getIni($this->modulesDir);
}
/**
* @throws Throwable
*/
public function setInfo(array $kv = [], array $arr = []): bool
{
if ($kv) {
$info = $this->getInfo();
foreach ($kv as $k => $v) {
$info[$k] = $v;
}
return Server::setIni($this->modulesDir, $info);
}
if ($arr) {
return Server::setIni($this->modulesDir, $arr);
}
throw new Exception('Parameter error');
}
public static function isEmptyArray($arr): bool
{
foreach ($arr as $item) {
if (is_array($item)) {
if (!self::isEmptyArray($item)) return false;
} elseif ($item) {
return false;
}
}
return true;
}
public function setModuleUid(string $uid): static
{
$this->uid = $uid;
$this->modulesDir = $this->installDir . $uid . DIRECTORY_SEPARATOR;
return $this;
}
}