check() ){ self::setProgressFailed('NO_ADMIN_PRIVILEGE'); return false; } //初始化 if(! self::initialize($vendorDir)){ self::setProgressFailed('INITIALIZE_FAILED'); return false; } logInfo("distribute mode: ",self::$config['distribute-mode']); //分发模式 if( self::$config['distribute-mode'] == 'install'){ self::install($vendorDir,$rootPkg,$vendorPkgs); } else{ self::upgrade($vendorDir,$rootPkg,$vendorPkgs); } return true; } private static function install($vendorDir,$rootPkg,$vendorPkgs){ //依赖库都已下载,默认先给个进度 self::setProgressStep1(100); //逐个依赖仓库操作 if(! self::postUpdateVendorPkgs($vendorDir,$vendorPkgs) ){ return false; } //顶层仓库操作 if(! self::postUpdateRootPkg($vendorDir,$rootPkg) ){ return false; } //全部操作完毕 self::setProgressOK(true); return true; } private static function upgrade($vendorDir,$rootPkg,$vendorPkgs){ //依赖库都已下载,默认先给个进度 self::setProgressStep1(100); //逐个依赖仓库操作 if(! self::postUpdateVendorPkgs($vendorDir,$vendorPkgs) ){ return false; } //顶层仓库操作 if(! self::postUpdateRootPkg($vendorDir,$rootPkg) ){ return false; } //全部操作完毕 self::setProgressOK(true); return true; } /* private static function createModuleIni($vendorDir,$vendorPkgs) { //[MODULE]节点内容 $content = '[MODULE]' . PHP_EOL; foreach($vendorPkgs as $i=>$pkg){ if( in_array($pkg->getName(),['a/distribute-helper']) ) continue; $cfgPath = pathJoin($vendorDir,$pkg->getName(),'composer.json'); $data = json_decode(file_get_contents($cfgPath), true); $moduleName = $data["distribute-helper"]["module-name"]; if(!$moduleName){ logError('bad format. no module-name node exists.',$cfgPath); return false; } $content .= $moduleName . '=' . $pkg->getName() . ',' . $pkg->getPrettyVersion() . PHP_EOL; } //[CONFIG]节点内容 //获取包信息 $repoDir = dirname($vendorDir); $packageInfo = self::getPackageInfo($vendorDir,$repoDir,$pkg); $moduleConfig = $packageInfo['helper']['module-config'] ? : array(); $content = '[CONFIG]' . PHP_EOL; foreach($moduleConfig as $i=>$cfg){ $content .= $cfg['name'] . '=' . $cfg['value'] . PHP_EOL; } //保存文件 file_put_contents(MODULEINI_PATH,$content); return true; }*/ private static function postUpdateVendorPkgs($vendorDir,$vendorPkgs) { $count = count($vendorPkgs); foreach($vendorPkgs as $i=>$pkg){ //获取包信息 $repoDir = pathJoin($vendorDir,$pkg->getName()); $packageInfo = self::getPackageInfo($vendorDir,$repoDir,$pkg); //获取当前包的module文件 if(! self::fetchModuleFiles($packageInfo) ){ self::setProgressFailed('FETCH_MODULE_FAILED'); return false; } self::setProgressStep2($count,$i,1); //获取当前包的common文件 if(! self::fetchCommonFiles($packageInfo) ){ self::setProgressFailed('FETCH_COMMON_FAILED'); return false; } self::setProgressStep2($count,$i,2); //拷贝当前包的config文件 self::setProgressStep2($count,$i,3); } return true; } private static function postUpdateRootPkg($vendorDir,$pkg) { //获取包信息 $repoDir = dirname($vendorDir); $packageInfo = self::getPackageInfo($vendorDir,$repoDir,$pkg); //拷贝copy-files文件 if(! self::copyFiles($packageInfo) ){ self::setProgressFailed('COPY_FILES_FAILED'); return false; } //替换文件内的宏变量 if(! self::macoFiles($packageInfo) ){ self::setProgressFailed('MACRO_FILES_FAILED'); return false; } //注册全局路径 if(! self::registerPath($packageInfo) ){ self::setProgressFailed('REGISTER_PATH_FAILED'); return false; } //注册自启动程序 if(! self::registerAutorun($packageInfo) ){ self::setProgressFailed('REGISTER_AUTORUN_FAILED'); return false; } //注册桌面快捷方式 if(! self::registerShortcut($packageInfo) ){ self::setProgressFailed('REGISTER_SHORTCUT_FAILED'); return false; } return true; } //初始化 private static function initialize($vendorDir) { //创建.distribute目录 $distributeDir = pathJoin(dirname($vendorDir),'.distribute'); if( !file_exists($distributeDir) ){ createDirectory($distributeDir); } //设置日志文件路径 if(! defined('LOG_PATH')){ $logPath = pathJoin($distributeDir,'log.txt'); define('LOG_PATH',$logPath); if(file_exists($logPath)) unlink($logPath); } //设置进度文件路径 if(! defined('PROGRESS_PATH')){ $progressPath = pathJoin($distributeDir,'progress.txt'); define('PROGRESS_PATH',$progressPath); if(file_exists($progressPath)) unlink($progressPath); } //创建module目录 $moduleDir = pathJoin(dirname($vendorDir),'module'); if( !file_exists($moduleDir) ){ createDirectory($moduleDir); } //解析安装包信息 $composerJson = pathJoin(dirname($vendorDir),'composer.json'); self::$app = json_decode(file_get_contents($composerJson), true); if(! self::$app ){ logError("failed to decode " . $composerJson); return false; } //获取部署配置信息 $cfgPath = pathJoin($distributeDir,'config.json'); if(! file_exists($cfgPath) ){ logInfo(".distribute/config.json file not exists,use default config. "); self::$config = defaultConfig(); } else{ self::$config = loadConfig($cfgPath); if(!self::$config){ logError("Failed to load distribute config",$cfgPath); return false; } logInfo("succeeded to decode config file -- .distribute/config.json"); } return true; } private static function setProgressStep1($percent) { $progress = 0.1 * $percent; file_put_contents(PROGRESS_PATH,strval($progress)); } private static function setProgressStep2($total,$index,$step) { $index = $index + $step/3.0; $progress = 10 + intval(90.0 * $index / $total); file_put_contents(PROGRESS_PATH,strval($progress)); } private static function setProgressFailed($msg) { file_put_contents(PROGRESS_PATH,"FAIL:" . $msg); } private static function setProgressOK($restart) { if($restart){ file_put_contents(PROGRESS_PATH,"OK:NEED_RESTART"); } else{ file_put_contents(PROGRESS_PATH,"OK:NO_RESTART"); } } //获取包相关信息 private static function getPackageInfo($vendorDir,$repoDir,$pkg) { $config = self::$config; $app = self::$app; $repoName = $pkg->getName(); $module_alias = $app["distribute-root"]["module-alias"]; $cfgPath = pathJoin($repoDir,'composer.json'); $data = json_decode(file_get_contents($cfgPath), true); $moduleName = $module_alias[$repoName] ? : $repoName; //获取安装目录 $rootDir = dirname($vendorDir); $commonDir = pathJoin($rootDir,'common'); $configDir = pathJoin($rootDir,'config',$moduleName); $moduleDir = pathJoin($rootDir,'module',$moduleName); //获取缓存目录 $cacheDir = pathJoin($config['cache-dir'],str_replace('/','-',$pkg->getName())); //返回包的相关信息 return array( "repoName" => $repoName, "version" => $pkg->getPrettyVersion(), "rootDir" => $rootDir, "cacheDir" => $cacheDir, "toolDir" => $config['tool-dir'], "ossHost" => $config['oss-host'], "moduleName" => $moduleName, "commonDir" => $commonDir, "configDir" => $configDir, "moduleDir" => $moduleDir, "helper" => $data["distribute-helper"], ); } //下载包module文件 private static function fetchModuleFiles($packageInfo) { $toolDir = $packageInfo['toolDir']; $cacheDir = $packageInfo['cacheDir']; $repoName = $packageInfo['repoName']; $version = $packageInfo['version']; $moduleDir = $packageInfo['moduleDir']; $ossHost = $packageInfo['ossHost']; $moduleFiles = $packageInfo['helper']['module-files'] ? : array(); foreach($moduleFiles as $fileInfo){ $fileName = $fileInfo['name']; //下载文件到缓存区 $filePath = downloadToDir($toolDir,$ossHost,$repoName,$fileName,$cacheDir); if(! $filePath ){ logError($repoName,"fetch module file failed",$fileName); return false; } logInfo("succeeded to fetch module file --",$repoName,$fileName); // 解压文件 if( isZipFile($fileName) ){ if(! unzipFile($toolDir,$filePath,$moduleDir)) { logError($repoName,"unzip module file failed",$fileName); return false; } } } return true; } //下载包common文件 private static function fetchCommonFiles($packageInfo) { $toolDir = $packageInfo['toolDir']; $cacheDir = $packageInfo['cacheDir']; $repoName = $packageInfo['repoName']; $version = $packageInfo['version']; $commonDir = $packageInfo['commonDir']; $ossHost = $packageInfo['ossHost']; $commonFiles = $packageInfo['helper']['common-files']? : array(); foreach($commonFiles as $fileInfo){ $fileName = $fileInfo['name']; $target = $fileInfo['target']; //下载文件到缓存区 $filePath = downloadToDir($toolDir,$ossHost,$repoName,$fileName,$cacheDir); if(! $filePath ){ logError($repoName,"fetch common file failed",$fileName); return false; } logInfo("succeeded to fetch common file --",$repoName,$fileName); // 解压文件 if( isZipFile($fileName) ){ $targetDir = pathJoin($commonDir,$target); if(! unzipFile($toolDir,$filePath,$targetDir)) { logError($repoName,"unzip common file failed",$fileName); return false; } } } return true; } //拷贝config文件 /* private static function copyConfigFiles($packageInfo) { $cacheDir = $packageInfo['cacheDir']; $repoName = $packageInfo['repoName']; $version = $packageInfo['version']; $configDir = $packageInfo['configDir']; $moduleDir = $packageInfo['moduleDir']; $configFiles = $packageInfo['helper']['config-files'] ? : array(); foreach($configFiles as $fileInfo){ $fileName = $fileInfo['name']; $targetName = $fileInfo['target']; $filePath = pathJoin($moduleDir,$fileName); if(! file_exists($filePath) ){ logError($repoName,"config file not exists",$filePath); return false; } if(!$fileInfo['override'] && file_exists($targetPath)){ logInfo($repoName,"skip copy config file",$targetPath); continue; } $targetPath = pathJoin($configDir,$targetName); if(! fileCopy($filePath,$targetPath) ){ logError($repoName,"config file copy failed",$filePath); return false; } } return true; }*/ //拷贝copy-files文件 private static function copyFiles($packageInfo) { $app = self::$app; $cacheDir = $packageInfo['cacheDir']; $repoName = $packageInfo['repoName']; $version = $packageInfo['version']; $rootDir = $packageInfo['rootDir']; $copyFiles = $app["distribute-root"]["copy-files"] ? : array(); foreach($copyFiles as $fileInfo){ $fileName = $fileInfo['path']; $targetName = $fileInfo['target']; $filePath = pathJoin($rootDir,$fileName); $targetPath = pathJoin($rootDir,$targetName); if(! file_exists($filePath) ){ logError("failed to copy file, file not exists.",$filePath); return false; } if(!$fileInfo['override'] && file_exists($targetPath)){ logInfo("skip copy file, file already exists",$targetPath); continue; } if( filedirCopy($filePath,$targetPath) ){ logInfo("succeeded to copy file",$fileName," -> ",$targetName); } else{ logError("failed to copy file, copy action failed.",$filePath); return false; } } return true; } private static function macoFiles($packageInfo) { $app = self::$app; $cacheDir = $packageInfo['cacheDir']; $repoName = $packageInfo['repoName']; $version = $packageInfo['version']; $rootDir = $packageInfo['rootDir']; $macroFiles = $app["distribute-root"]["macro-files"] ? : array(); $appDir = str_replace('\\','/',$rootDir); $rootDirUp2 = dirname(dirname($rootDir)); $appdataDir = pathJoin($rootDirUp2,'appdata'); $tmpdataDir = pathJoin($rootDirUp2,'tmpdata'); $macros = array( '{sis31.appdir}' => $appDir, '{sis31.appdata}' => $appdataDir, '{sis31.tmpdata}' => $tmpdataDir, ); foreach($macroFiles as $fileInfo){ $fileName = $fileInfo['path']; $filePath = pathJoin($rootDir,$fileName); if(! file_exists($filePath) ){ logError("failed to replace macro file, file not exists.",$filePath); return false; } $targetName = $fileInfo['target']; $targetPath = pathJoin($rootDir,$targetName); if( replaceMacro($filePath,$targetPath,$macros) ){ logInfo("succeeded to replace macro file",$fileName); } else{ logError("failed to replace macro file",$filePath); return false; } } return true; } private static function registerPath($packageInfo) { $app = self::$app; $rootDir = $packageInfo['rootDir']; $removePath = $app["distribute-root"]["remove-path"] ? : array(); $registerPath = $app["distribute-root"]["register-path"] ? : array(); $arrRemovePattern = array(); foreach($removePath as $item){ $pattern = pathJoin($rootDir,$item['pattern']); array_push($arrRemovePattern,$pattern); } $arrAddPath = array(); foreach($registerPath as $item){ $path = pathJoin($rootDir,$item['path']); array_push($arrAddPath,$path); } $removePathes = array(); $env = new WinEnvPath(); if(! $env->updatePath($arrRemovePattern,$arrAddPath,$removePathes) ){ logError('failed to register path'); return false; } foreach($removePathes as $path){ logInfo('succeeded to remove path',$path); } foreach($arrAddPath as $path){ logInfo('succeeded to add path',$path); } return true; } private static function registerAutorun($packageInfo) { $app = self::$app; $rootDir = $packageInfo['rootDir']; $removeAutorun = $app["distribute-root"]["remove-autorun"] ? : array(); $regAutorun = $app["distribute-root"]["register-autorun"] ? : array(); $auto = new WinAutorun(); foreach($removeAutorun as $item){ if(! $auto->remove($item['name']) ){ logError('failed to remove autorun',$item['name']); return false; } logInfo('succeeded to remove autorun',$item['name']); } foreach($regAutorun as $item){ $cmd = pathJoin($rootDir,$item['path']); if(! $auto->register($item['name'],$cmd) ){ logError('failed to register autorun',$item['name']); return false; } logInfo('succeeded to register autorun',$item['name']); } return true; } private static function registerShortcut($packageInfo) { $app = self::$app; $rootDir = $packageInfo['rootDir']; $removeShortcut = $app["distribute-root"]["remove-shortcut"] ? : array(); $regShortcut = $app["distribute-root"]["register-shortcut"] ? : array(); $sc = new WinDesktopShortcut(); foreach($removeShortcut as $item){ if(! $sc->remove($item['name']) ){ logError('failed to remove shortcut',$item['name']); return false; } logInfo('succeeded to remove shortcut',$item['name']); } foreach($regShortcut as $item){ $path = pathJoin($rootDir,$item['path']); if(! $sc->register($item['name'],$path,$item['desc']) ){ logError('failed to register shortcut',$item['name']); return false; } logInfo('succeeded to register shortcut',$item['name']); } return true; } }