public function actionAvatar() { $fileParts = pathinfo($_FILES['avatar']['name']); if ($_FILES['avatar']['error']) { $this->renderJson([], -1, yii::t('user', 'upload failed')); } if ($_FILES['avatar']['size'] > static::AVATAR_SIZE) { $this->renderJson([], -1, yii::t('user', 'attached\'s size too large')); } if (!in_array(strtolower($fileParts['extension']), \Yii::$app->params['user.avatar.extension'])) { $this->renderJson([], -1, yii::t('user', 'type not allow', ['types' => join(', ', \Yii::$app->params['user.avatar.extension'])])); } $tempFile = $_FILES['avatar']['tmp_name']; $baseName = sprintf('%s-%d.%s', date("YmdHis", time()), rand(10, 99), $fileParts['extension']); $newFile = User::AVATAR_ROOT . $baseName; $urlFile = GlobalHelper::formatAvatar($baseName); $targetFile = sprintf("%s/web/%s", rtrim(\Yii::$app->basePath, '/'), ltrim($newFile, '/')); $ret = move_uploaded_file($tempFile, $targetFile); if ($ret) { $user = User::findOne($this->uid); $user->avatar = $baseName; $ret = $user->save(); } $this->renderJson(['url' => $urlFile], !$ret, $ret ?: yii::t('user', 'update avatar failed')); }
/** * @param \yii\base\Action $action * @return bool */ public function beforeAction($action) { parent::beforeAction($action); if (!GlobalHelper::isValidAdmin()) { throw new \Exception('项目管理员尚未通过其它项目管理员的审核,无操作项目权限:)'); } return true; }
/** * @param \yii\base\Action $action * @return bool */ public function beforeAction($action) { parent::beforeAction($action); if (!GlobalHelper::isValidAdmin()) { throw new \Exception(yii::t('conf', 'you are not active')); } return true; }
/** * 获取远程服务器要操作的任务命令 * * @param $task string * @param $version string * @return string string */ public static function getRemoteTaskCommand($task, $version) { $tasks = GlobalHelper::str2arr($task); if (empty($tasks)) { return ''; } $cmd = []; $workspace = rtrim(Project::getDeployWorkspace($version), '/'); $version = Project::getReleaseVersionDir($version); $pattern = ['#{WORKSPACE}#', '#{VERSION}#']; $replace = [$workspace, $version]; foreach ($tasks as $task) { $cmd[] = preg_replace($pattern, $replace, $task); } return join(' && ', $cmd); }
/** * 同步代码之后触发任务 * 所有目标机器都部署完毕之后,做一些清理工作,如删除缓存、重启服务(nginx、php、task) * * @return bool */ public function postRelease($version) { $tasks = GlobalHelper::str2arr($this->getConfig()->post_release); if (empty($tasks)) { return true; } $cmd = []; $workspace = rtrim(Project::getDeployWorkspace($version), '/'); $version = Project::getReleaseVersionDir($version); $pattern = ['#{WORKSPACE}#', '#{VERSION}#']; $replace = [$workspace, $version]; foreach ($tasks as $task) { $cmd[] = preg_replace($pattern, $replace, $task); } $command = join(' && ', $cmd); return $this->runRemoteCommand($command); }
protected final function runRemoteCommand($command) { $this->log = ''; $needs_tty = ''; foreach (GlobalHelper::str2arr($this->getConfig()->hosts) as $remoteHost) { $localCommand = 'ssh ' . $needs_tty . ' -p ' . $this->getHostPort($remoteHost) . ' -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ' . $this->getConfig()->release_user . '@' . $this->getHostName($remoteHost); $remoteCommand = str_replace('"', '\\"', trim($command)); $localCommand .= ' "sh -c \\"' . $remoteCommand . '\\"" '; static::log('Run remote command ' . $remoteCommand); $log = $this->log; $this->status = $this->runLocalCommand($localCommand); $this->log = $log . (($log ? PHP_EOL : '') . $remoteHost . ' : ' . $this->log); if (!$this->status) { return false; } } return true; }
/** * 获取远程服务器要操作的任务命令 * * @param $task string * @param $version string * @return string string */ public static function getRemoteTaskCommand($task, $version) { $tasks = GlobalHelper::str2arr($task); if (empty($tasks)) { return ''; } // 可能要做一些依赖环境变量的命令操作 $cmd = ['source /etc/profile']; $workspace = Project::getTargetWorkspace(); $version = Project::getReleaseVersionDir($version); $pattern = ['#{WORKSPACE}#', '#{VERSION}#']; $replace = [$workspace, $version]; // 简化用户切换目录,直接切换到当前的版本目录:{release_library}/{project}/{version} $cmd[] = "cd {$version}"; foreach ($tasks as $task) { $cmd[] = preg_replace($pattern, $replace, $task); } return join(' && ', $cmd); }
public function diffWithOnline($file) { $localSourceDir = $this->config->getDeployFromDir(); $remoteSourceDir = $this->config->getTargetWorkspace(); $cmd[] = "cat {$remoteSourceDir}/{$file}"; $command = implode(' && ', $cmd); $host = GlobalHelper::str2arr($this->config->hosts)[0]; if ($this->runRemoteCommand($command, 0, $host)) { $contentOld = explode(PHP_EOL, substr($this->log, strlen($host . ' : '))); array_walk($contentOld, function (&$line) { $line = rtrim($line, "\r\n"); }); } else { $contentOld = []; } $contentNew = file("{$localSourceDir}/{$file}"); array_walk($contentNew, function (&$line) { $line = rtrim($line, "\r\n"); }); $diff = new \Diff($contentOld, $contentNew); return $diff->render(new \Diff_Renderer_Html_Array()); }
/** * 将多个文件/目录通过ansible传输到指定的多个目标机 * * ansible 不支持 rsync模块, 改用宿主机 tar 打包, ansible 并发传输到目标机临时目录, 目标机解压 * * @param $version * @param string $files 相对仓库文件/目录路径, 空格分割 * @param array $remoteHosts */ public function copyFiles($version, $files = '*', $remoteHosts = []) { // 1. 打包 $excludes = GlobalHelper::str2arr($this->getConfig()->excludes); $packagePath = Project::getDeployPackagePath($version); $packageCommand = sprintf('cd %s && tar -p %s -cz -f %s %s', escapeshellarg(rtrim(Project::getDeployWorkspace($version), '/') . '/'), $this->excludes($excludes), escapeshellarg($packagePath), $files); $ret = $this->runLocalCommand($packageCommand); if (!$ret) { return false; } // 2. 传输文件 $releasePackage = Project::getReleaseVersionPackage($version); $ret = $this->copyFilesByAnsibleCopy($packagePath, $releasePackage); if (!$ret) { return false; } // 3. 解压 $releasePath = Project::getReleaseVersionDir($version); $unpackageCommand = sprintf('cd %1$s && tar --no-same-owner -pm -C %1$s -xz -f %2$s', $releasePath, $releasePackage); $ret = $this->runRemoteCommandByAnsibleShell($unpackageCommand); return $ret; }
public function actionAvatar() { $fileParts = pathinfo($_FILES['avatar']['name']); if ($_FILES['avatar']['error']) { $this->renderJson([], -1, '上传附件失败'); } if ($_FILES['avatar']['size'] > static::AVATAR_SIZE) { $this->renderJson([], -1, '文件过大'); } if (!in_array(strtolower($fileParts['extension']), \Yii::$app->params['user.avatar.extension'])) { $this->renderJson([], -1, '上传附件失败,附件格式只支持:' . join(', ', \Yii::$app->params['user.avatar.extension'])); } $tempFile = $_FILES['avatar']['tmp_name']; $baseName = sprintf('%s-%d.%s', date("YmdHis", time()), rand(10, 99), $fileParts['extension']); $newFile = GlobalHelper::formatAvatar($baseName); $targetFile = sprintf("%s/web/%s", rtrim(\Yii::$app->basePath, '/'), ltrim($newFile, '/')); $ret = move_uploaded_file($tempFile, $targetFile); if ($ret) { $user = User::findOne($this->uid); $user->avatar = $baseName; $ret = $user->save(); } $this->renderJson(['url' => $newFile], !$ret, $ret ?: '更新头像失败'); }
/** * 获取提交历史 * * @return array */ public function getCommitList($branch = 'master', $count = 20) { // 先更新 $destination = Project::getDeployFromDir(); $this->updateRepo($branch, $destination); $cmd[] = sprintf('cd %s ', $destination); $cmd[] = '/usr/bin/env git log -' . $count . ' --pretty="%h - %an %s" '; $command = join(' && ', $cmd); $result = $this->runLocalCommand($command); if (!$result) { throw new \Exception(\yii::t('walle', 'get commit log failed') . $this->getExeLog()); } $history = []; // 总有一些同学没有团队协作意识,不设置好编码:( $log = GlobalHelper::convert2Utf8($this->getExeLog()); $list = explode(PHP_EOL, $log); foreach ($list as $item) { $commitId = substr($item, 0, strpos($item, '-') - 1); $history[] = ['id' => $commitId, 'message' => $item]; } return $history; }
/** * 获取当前进程配置的目标机器host列表 */ public static function getHosts() { return GlobalHelper::str2arr(static::$CONF->hosts); }
/** * rsync 同步文件 * * @param $remoteHost 远程host,格式:host 、host:port * @return bool */ public function syncFiles($remoteHost, $version) { $excludes = GlobalHelper::str2arr($this->getConfig()->excludes); $command = sprintf('rsync -avzq --rsh="ssh -p %s" %s %s %s%s:%s', $this->getHostPort($remoteHost), $this->excludes($excludes), rtrim(Project::getDeployWorkspace($version), '/') . '/', $this->getConfig()->release_user . '@', $this->getHostName($remoteHost), Project::getReleaseVersionDir($version)); return $this->runLocalCommand($command); }
/** * 获取提交历史 * * @return array */ public function getCommitList($branch = 'master', $count = 30) { // 先更新 $destination = Project::getDeployFromDir(); $this->updateRepo($branch, $destination); $cmd[] = sprintf('cd %s ', static::getBranchDir($branch, $this->getConfig()->repo_mode == Project::REPO_TAG ?: false)); $cmd[] = $this->_getSvnCmd('svn log --xml -l' . $count); $command = join(' && ', $cmd); $result = $this->runLocalCommand($command); if (!$result) { throw new \Exception('获取提交历史失败:' . $this->getExeLog()); } // 总有一些同学没有团队协作意识,不设置好编码:( $log = GlobalHelper::convert2Utf8($this->getExeLog()); return array_values(static::formatXmlLog($log)); }
<a href="#"> 查看所有通知 <i class="icon-arrow-right"></i> </a> </li> --> </ul> </li> <?php } ?> <li class="light-blue"> <a data-toggle="dropdown" href="javascript:;" class="dropdown-toggle"> <img class="nav-user-photo" src="<?php echo GlobalHelper::formatAvatar($user->avatar); ?> "> <span class="user-info" style="top:12px"><?php echo $userName; ?> </span> <i class="icon-caret-down"></i> </a> <ul class="user-menu pull-right dropdown-menu dropdown-yellow dropdown-caret dropdown-close"> <!-- 设置功能暂无 <li> <a href="javascript:;"> <i class="icon-cog"></i> 设置
/** * 获取要发布的文件列表 * * @return array|string */ public function getCommandFiles() { if ($this->file_transmission_mode == static::FILE_TRANSMISSION_MODE_FULL) { return '.'; } elseif ($this->file_transmission_mode == static::FILE_TRANSMISSION_MODE_PART && $this->file_list) { $fileList = GlobalHelper::str2arr($this->file_list); $commandFiles = join(' ', $fileList); return trim($commandFiles); } else { throw new \InvalidArgumentException('file list empty'); } }
/** * @param Project $project * @param TaskModel $task * @return bool * @throws \Exception */ protected function _packageFiles(Project $project, TaskModel $task) { $version = $task->link_id; $files = $task->getCommandFiles(); $excludes = GlobalHelper::str2arr($project->excludes); $packagePath = Project::getDeployPackagePath($version); $packageCommand = sprintf('cd %s && tar -p %s -cz -f %s %s', escapeshellarg(rtrim(Project::getDeployWorkspace($version), '/') . '/'), $this->excludes($excludes), escapeshellarg($packagePath), $files); $ret = $this->runLocalCommand($packageCommand); if (!$ret) { throw new \Exception(yii::t('walle', 'package error')); } return true; }
/** * 需要项目管理员权限 * * @throws \Exception */ protected function validateAdmin() { if (!GlobalHelper::isValidAdmin()) { throw new \Exception('非管理员不能操作:('); } }
/** * 获取文件和版本号列表 * * @param TaskModel $task * @return array */ public function getFileAndVersionList(TaskModel $task) { $fileList = GlobalHelper::str2arr($task->file_list); $fileAndVersion = []; foreach ($fileList as $file) { list($file, $version) = array_pad(StringHelper::explode($file, ' ', true, true), 2, null); $fileAndVersion[] = ['file' => $file, 'version' => $version]; } return $fileAndVersion; }
$sideBarMenus = $this->context->sideBar; } elseif (!empty($this->context->module->menus)) { $sideBarMenus = $this->context->module->menus; } else { $sideBarMenus = [['label' => '用户管理', 'items' => [['label' => '用户列表', 'url' => '/user/list'], ['label' => '添加用户', 'url' => '/user/add']]], ['label' => Yii::t('w', 'menu task list'), 'url' => '/task/index'], ['label' => Yii::t('w', 'menu submit task'), 'url' => '/task/submit'], ['label' => Yii::t('w', 'menu file md5'), 'url' => '/walle/check'], ['label' => Yii::t('w', 'menu config project'), 'url' => '/conf', 'visible' => \Yii::$app->user->identity->role == app\models\User::ROLE_ADMIN]]; } ?> <aside class="main-sidebar"> <section class="sidebar"> <!-- Sidebar user panel --> <div class="user-panel"> <div class="pull-left image"> <!--<img src="<?php echo \app\components\GlobalHelper::formatAvatar(\Yii::$app->user->identity->avatar); ?> " class="img-circle" alt="User Image"/>--> <img src="<?php echo $directoryAsset; ?> /img/user2-160x160.jpg" class="img-circle" alt="User Image"/> </div> <div class="pull-left info"> <?php /* <p><?= \Yii::$app->user->identity->username ?></p> */ ?> <p> 你好,<?php echo \Yii::$app->user->identity->username; ?> </p>
/** * 需要项目管理员权限 * * @throws \Exception */ protected function validateAdmin() { if (!GlobalHelper::isValidAdmin()) { throw new \Exception(\yii::t('walle', 'you are not the manager')); } }
/** * 获取两个版本的差异 * * @ return array */ public function getVersionDiff($old, $new) { $destination = Project::getDeployFromDir(); $cmd[] = sprintf('cd %s ', $destination); $cmd[] = sprintf('/usr/bin/env git reset -q --hard %s', $new); $cmd[] = sprintf('/usr/bin/env git diff %s %s --name-status', $old, $new); $command = implode(' && ', $cmd); $result = $this->runLocalCommand($command); $output = explode(PHP_EOL, $this->getExeLog()); $diff = []; $excludes = GlobalHelper::str2arr($this->config->excludes); array_push($excludes, '*.git*'); array_push($excludes, '.svn*'); array_walk($excludes, function (&$item) { $item = '~^([A-Z])\\s+' . str_replace('\\*', '.*', preg_quote($item)) . '~Ui'; }); foreach ($output as $line) { if (!preg_filter($excludes, 'exclude', $line) && preg_match('~^([A-Z])\\s+(\\S+)$~', $line, $match)) { if ($file = realpath("{$destination}/{$match[2]}")) { $diff[$file] = ['status' => $match[1], 'file' => $file]; } } } return $diff; }