手机浏览 RSS 2.0 订阅 膘叔的简单人生 , 腾讯云RDS购买 | 超便宜的Vultr , 注册 | 登陆
浏览模式: 标准 | 列表2024年11月的文章

nginx+workerman做自动CI(初级)

 本文是利用nginx的proxypass来做代理到workerman创建的webserver上,从而使得github的git webhook可以起作用。

代码不复杂

1、准备一个composer.json,内容超短:

JavaScript代码
  1. {"name":"auto deploy","authors":[{"name":"gouki","email":"neatcn@qq.com"},"require":{"workerman/workerman":"dev-master"},"license":"MIT"]}  
2、复制下面的代码,并赋予可执行权限(也可以不赋予,直接使用php xxx.php start 即可)
PHP代码
  1. #!/usr/bin/env php  
  2. <?php  
  3. /** 
  4.  * composer.json的内容,如果不依赖其他系统,则runtime目录设置为/,同时设置PORT 
  5.  * {"name":"auto deploy","authors":[{"name":"gouki","email":"neatcn@qq.com"},"require":{"workerman/workerman":"dev-master"},"license":"MIT"]} 
  6.  * 使用方法: 
  7.  * php {filename} start -d 
  8.  * php {filename} reload -g -d 
  9.  * php {filename} stop -g 
  10.  */  
  11.   
  12. use Workerman\Connection\ConnectionInterface;  
  13. use Workerman\Worker;  
  14.   
  15. include __DIR__ . "/vendor/autoload.php";  
  16.   
  17. // define('ROOT_PATH', __DIR__);  
  18. //http server的端口,用于给nginx做反代,不要和其他程序有冲突  
  19. define('HTTP_SERVER'"http://0.0.0.0:8002");  
  20. //存放LOG的位置,记得以 / 结尾  
  21. define('RUNTIME_PATH', __DIR__ . "/runtime/");  
  22.   
  23. //commit message中的关键字,检测到后才需要更新,如果留空。则全部更新  
  24. // define('DEPLOY_KEYWORD','deploy');  
  25. Worker::$pidFile = RUNTIME_PATH . str_replace('/''_'__FILE__) . ".pid";  
  26.   
  27. $config = [  
  28.     'demo.neatstudio.com' => [  
  29.         'target'   => '/server/wwwroot/yzhan/neatstudio.com',  
  30.         'secret'   => '123456',  
  31.         //commit message中的关键字,检测到后才需要更新,如果留空。则全部更新  
  32.         'keyword'  => 'deploy',  
  33.         'commands' => [],  
  34.     ]  
  35. ];  
  36.   
  37. $worker = new Worker(HTTP_SERVER);  
  38. $worker->count = 1;  
  39. $worker->reloadable = false;  
  40. $worker->onWorkerStart = function() {  
  41. };  
  42. $worker->onError = function(ConnectionInterface $connection) {  
  43.     $connection->close(resp_error_msg("ERROR", ['request' => func_get_args()]));  
  44. };  
  45.   
  46. $worker->onMessage = function(ConnectionInterface $connection$datause ($config) {  
  47.     // echo(sprintf("[%s]IP: %s:%s , Data: %s", date("Y-m-d H:i:s"), $connection->getRemoteIp(), $connection->getRemotePort(), var_export($data, true)));  
  48.     $server = $data['server'];  
  49.     if($server['CONTENT_TYPE'] === "application/x-www-form-urlencoded"){  
  50.         $post = json_decode($data['post']['payload'], true);  
  51.     } else{  
  52.         $post = $data['post'];  
  53.     }  
  54.     $repository = $post['repository']['name'] ?? "";  
  55.     $commitMsg = $post['head_commit']['message'] ?? "";  
  56.   
  57.     if(!isset($config[$repository])){//配置资源  
  58.         $connection->close(resp_error_msg('GIT资源未配置'));  
  59.         return;  
  60.     }  
  61.     $deployKeyword = $config[$repository]['keyword'];  
  62.     //只有有关键字的时候才会部署  
  63.     if($commitMsg && $deployKeyword && strpos($commitMsg$deployKeyword) === false){  
  64.         $connection->close(resp_error_msg('未检测到关键字,不用部署'));  
  65.         return;  
  66.     }  
  67.     // echo $server['HTTP_X_HUB_SIGNATURE'], "\n";  
  68.     // echo "sha1=" . hash_hmac('sha1', $GLOBALS['HTTP_RAW_REQUEST_DATA'], $config[$repository]['secret']), "\n";  
  69.   
  70.     if(strpos($server['HTTP_USER_AGENT'], "GitHub-Hookshot/") === false ||  
  71.        $server['HTTP_X_HUB_SIGNATURE'] !== "sha1=" . hash_hmac('sha1'$GLOBALS['HTTP_RAW_REQUEST_DATA'], $config[$repository]['secret'])){  
  72.         $connection->close(resp_success_msg('数据校验失败'));  
  73.         return;  
  74.     }  
  75.   
  76.     $ret = '';  
  77.     //开始执行  
  78.     $commands = [  
  79.         "cd {$config[$repository]['target']} ",  
  80.         "git fetch --all",  
  81.         "git reset --hard origin/master",  
  82.         "./yii cache/flush-schema --interactive=0",  
  83.     ];  
  84.     $commands = array_merge($commands$config[$repository]['commands'] ?? []);  
  85.     exec(join(" && "$commands), $ret);  
  86.     // exec("cd {$config[$repository]['target']} && git fetch --all && git reset --hard origin/master && ./yii cache/flush-schema --interactive=0 ", $ret);  
  87.     $connection->close(resp_success_msg('更新成功'$ret));  
  88. };  
  89. Worker::$logFile = RUNTIME_PATH . "workerman.log";  
  90. Worker::runAll();  
  91.   
  92. function resp_json($data$message = ''$is_error = 0)  
  93. {  
  94.     $result['status'] = 0;  
  95.     if($is_error){  
  96.         $result['error'] = $data;  
  97.     } else{  
  98.         $result['status'] = 1;  
  99.         $result['datas'] = $data;  
  100.     }  
  101.     $result['message'] = $message;  
  102.     return json_encode($result, JSON_UNESCAPED_UNICODE);  
  103. }  
  104.   
  105. function resp_success($data)  
  106. {  
  107.     return resp_json($data);  
  108. }  
  109.   
  110. function resp_success_msg($message$data = [])  
  111. {  
  112.     return resp_json($data$message);  
  113. }  
  114.   
  115. function resp_error($data)  
  116. {  
  117.     return resp_json($data'', 1);  
  118. }  
  119.   
  120. function resp_error_msg($message$data = [])  
  121. {  
  122.     return resp_json($data$message, 1);  
  123. }  

是不是基本上控制 在100行内?因为访问量不会太大。所以我设置worker->count = 1,即,只启用一个子进程。

有人会说了,其实写一个PHP文件就可以了,设置为web目录指定一个域名不就完事了吗?是的,你说的这样其实也行,但有一点,如果你需要执行git命令还有使用exec命令,可能你的权限就不足了。而且。如果你的GIT是 采用root权限来git pull的。你拉回来的文件的owner都是root,这时候还需要执行chown -R www-data:www-data . 来处理,如果你是当成web项目来做,可能你就没有这个权限。

因此workerman就有了这样的功能。毕竟他是以root权限来运行的(也可以指定其他权限,如果指定非www-data[ubuntu/debian],你还得有权限设置目录的用户组)

-----

对比wallE和那个女娲系统,我这个是超级简单了。只有一个文件。而且不能远程操作(远程操作建议使用本程序+ansible),是不是也简单的够你用了,至少比以前写的 每分钟执行git pull一次好很多,workerman也支持多线程和多进程。性能也不差

 

mac finder中的cmd+x/cmd+v

 如果直接在finder中cmd+x/cmd+v,是没有任何作用的。原来一直以为只有cmd+c/cmd+v,然后再去删除原来的。或者。。。。拖动文件

其实,cmd+c/cmd+option+v,就相当于剪切了!
这个快捷键,从Lion版开始就有了,只是之前真心不知道。

Yii2 ErrorHandler的自定义

 不想多说这个,这一篇写的很好:Yii2组件分析:错误处理(ErrorHandle),我在这里只是想多说一两句:Yii::$app->getErrorHandler()->register(),这一条非常重要。

为什么多提这一句,是因为我在开发的过程中,用了不少的module,想为每一个module都单独设置一个errorHandler,所以特别的在module的init里加入了:Yii::$app->setComponents(['errorHandler'=>['class'=>'CustomErrorHandler']]);然而并不起作用,因为就少了那一句:Yii::$app->getErrorHandler()->register();

原因就是上文链接中提到的。Yii2在register方法里对输出做了自定义的处理,如果你不做一次register,你所使用的,将一直是配置文件中所配置的那个ErrorHandler。

这也就说明了,Yii::$app->setComponents()这个方法,还是要根据实际 情况来的。不是说临时改点变量,就可以直接用的。慎重

symlink-hook: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory

出现如标题错误的最大可能原因是。。。

你当前所在的目录被改名或者被删除了。。,尝试cd /回到根目录下再处理

Tags: linux, getcwd

tinymce 5 的dialog不再支持iframe了

 尝试整个vue+tinymce的时候遇到点问题(之前说过,本来是用quillJS的。但如果要发表的内容支持那些微信编辑器里复制过来的内容。quill自己定义过的一些虚拟DOM就不支持了)

希望是美好的,实现起来是麻烦的,最后我放弃所有的选项,改用弹框iframe的形式。然而,问题就这么来了,tinymce5的dialog居然不支持iframe了。比如你看这个:https://github.com/tinymce/tinymce/issues/4786,官方直接说不支持了。NND

不过有人提示说,可以利用htmlpanel,直接在htmlpanel的html标签里,用<iframe。。。然后我试了一下。。居然真的OK

好吧,直接参考 这个了!https://github.com/tinymce/tinymce/issues/4786#issuecomment-463827289

JS文件:

JavaScript代码
  1. function FileManager(callback, value, meta) {  
  2.         var windowManagerURL = "/FilManage";// filemanager path  
  3.    
  4.         var windowManagerCSS = '<style type="text/css">' +  
  5.             '.tox-dialog {max-width: 100%!important; width:97.5%!important; overflow: hidden; height:95%!important; border-radius:0.25em;}' +  
  6.             '.tox-dialog__header{ display:none!important; }' +// for custom header in filemanage  
  7.             '.tox-dialog__footer { display: none!important; }' +// for custom footer in filemanage  
  8.             '.tox-dialog__body { padding: 0!important; }' +  
  9.             '.tox-dialog__body-content > div { height: 100%; overflow:hidden}' +   
  10.             '</style > ';  
  11.         window.tinymceCallBackURL = '';  
  12.         window.tinymceWindowManager = tinymce.activeEditor.windowManager;  
  13.         tinymceWindowManager.open({  
  14.             title: '',  
  15.             body: {  
  16.                 type: 'panel',  
  17.                 items: [{  
  18.                     type: 'htmlpanel',  
  19.                     html: windowManagerCSS+ '<iframe src="' + windowManagerURL + '"  frameborder="0" style="width:100%; height:100%"></iframe>'  
  20.                 }]  
  21.             },  
  22.             buttons: [] ,  
  23.             onClose: function () {  
  24.                 if (tinymceCallBackURL!='')  
  25.                     callback(tinymceCallBackURL, {}); //to set selected file path  
  26.             }   
  27.             
  28.         } );  
  29.     }  

iframe中:

JavaScript代码
  1. var windowManager = top != undefined && top.tinymceWindowManager != undefined ? top.tinymceWindowManager : '';  
  2.   
  3.   
  4.  if (windowManager != '') {  
  5.         if (top.tinymceCallBackURL != undefined)  
  6.             top.tinymceCallBackURL = path;  
  7.             windowManager.close();  
  8.     }  

 

Tags: tinymce