團隊開發配合SVN HOOKS同步更新在線服務器源碼
最近為了協調整個開發團隊的開發過程,讓團隊協作更加流暢,考慮減少開發人員更新代碼維護代碼的中間環節,於是考慮使用了SVN服務端HOOKS
SVN服務端的 HOOKS 存在於每個 Project 倉庫的hooks目錄,裏面的 *.tmpl 是hooks腳本模板,我使用的是 windows 來做內網源碼版本 服務器系統,所以使用 *.bat 批處理文件來做 Hooks腳本! 但是總所周知 *.bat 批處理文件能執行的任務有限,所以我的批處理只是吧參數引導到PHP腳本上,由PHP腳本來實現我所需要的結果。
一、首先提高 svn 服務程序的權限,修改 "服務" 中 SVN 服務程序的登錄帳戶為超級管理員
二、編寫批處理。因為我只是需要在開發人員提交腳本後執行我的任務,所以只編寫了 post-commit.bat 批處理引導到了PHP腳本 post-commit.php上CODE:
@echo off
setlocal
SET PHP=E:\PHP5\php.exe
%PHP% -f %1\hooks\post-commit.php %*
關於hooks腳本,各位可以看這裏 http://www.subversion.org.cn/svn ... #svn.ref.reposhooks
三、建立 post-commit.php 在每次提交試執行判斷是否需要執行同步操作
我這裏加了 SVN 賬戶判斷,以便只有特定的用戶才有權限向線上服務器同步源碼
還加了[UPTO_RUN_SERVER] 標記,只有特定的用戶在提交時,加入了這個標記才會觸發同步到在線服務器的工作
四、建立一個臨時目錄用於從版本倉庫抽取需要更新的文件,如:E:\svn_tmp\MY_PROJECT_NAME
五、至於如何在團隊協同開發中部署這個應用,或如何更合理有效和安全,各位可以發揮一下想象力
以下是 post-commit.php 代碼的主要部分,有BUG僅供參考
[php]
<?php
//-----------------------------
// 初始化設置
//-----------------------------
//臨時更新目錄,用於svn checkout 得到最新的文件後,上傳到FTP
$TMP_UPDATE_DIR = "E:\\svn_tmp\\MY_PROJECT_NAME";
//獲得當前更新的log
$svnlook_log = "\"C:\\Program Files\\VisualSVN Server\\bin\\svnlook.exe\" log -r {$argv[2]} {$argv[1]}";
//獲得當前更新者帳戶名
$svnlook_author = "\"C:\\Program Files\\VisualSVN Server\\bin\\svnlook.exe\" author -r {$argv[2]} {$argv[1]}";
//更新最新的源碼到臨時更新目錄
$svn_update = "\"C:\\Program Files\\VisualSVN Server\\bin\\svn.exe\" update -r {$argv[2]} {$TMP_UPDATE_DIR}";
//有權限更新到運行服務器的svn帳戶
$upto_run_managers = array('terry39', 'user02', 'user03', 'user04');
//更新狀態記錄文件
$update_status_file = "E:\\svn_tmp\\MY_PROJECT_NAME_update_status.txt";
$output = array();
exec($svnlook_log, $output);
$log = $output;
$output = array();
exec($svnlook_author, $output);
$author = $output;
//-----------------------------
// 函數
//-----------------------------
/**
* 在FTP服務器上創建目錄
*
* @author terry39
*/
function ftp_create_dir($path)
{
global $ftp;
$dir=split("/", $path);
$path="";
$ret = true;
for ($i=0;$i<count($dir);$i++)
{
$path.="/".$dir[$i];
if(!@ftp_chdir($ftp,$path)){
@ftp_chdir($ftp,"/");
if(!@ftp_mkdir($ftp,$path)){
$ret=false;
break;
}
}
}
return $ret;
}
/**
* 刪除 FTP 中指定的目錄
*
* @param resource $ftp_stream The link identifier of the FTP connection
* @param string $directory The directory to delete
*
* @author terry39
*/
function ftp_rmdirr($ftp_stream, $directory)
{
if (!is_resource($ftp_stream) ||
get_resource_type($ftp_stream) !== 'FTP Buffer') {
return false;
}
// Init
$i = 0;
$files = array();
$folders = array();
$statusnext = false;
$currentfolder = $directory;
// Get raw file listing
$list = ftp_rawlist($ftp_stream, $directory, true);
foreach ($list as $current) {
if (empty($current)) {
$statusnext = true;
continue;
}
if ($statusnext === true) {
$currentfolder = substr($current, 0, -1);
$statusnext = false;
continue;
}
$split = preg_split('[ ]', $current, 9, PREG_SPLIT_NO_EMPTY);
$entry = $split[8];
$isdir = ($split[0]{0} === 'd') ? true : false;
// Skip pointers
if ($entry === '.' || $entry === '..') {
continue;
}
if ($isdir === true) {
$folders[] = $currentfolder . '/' . $entry;
} else {
$files[] = $currentfolder . '/' . $entry;
}
}
foreach ($files as $file) {
ftp_delete($ftp_stream, $file);
}
rsort($folders);
foreach ($folders as $folder) {
ftp_rmdir($ftp_stream, $folder);
}
return ftp_rmdir($ftp_stream, $directory);
}
/**
* 把更新到的文件列表上傳到服務器上
*
* 更新的同時記錄更新日志,如過有一個文件或者目錄更新失敗,則返回錯誤
*
* @param array $update_list
* @return bool
*
* @author terry39
*/
function update_to_ftp($update_list)
{
global $argv, $ftp, $author_name, $TMP_UPDATE_DIR;
$ftp_update_logfile='E:\svn_tmp\ftp_MY_PROJECT_NAME_upload.log'; //執行更新的日志文件
$ftp_root_dir = '/'; //服務器上的地址源碼對應的起始目錄
$log = "";
$log .= date('Y-m-d H:i:s') . " BEGIN UPDATE TO FTP\n";
$log .= date('Y-m-d H:i:s') . " Reversion: {$argv[2]}\n";
$log .= date('Y-m-d H:i:s') . " Author: {$author_name}\n";
$ftp = ftp_connect('FTP服務器地址');
$ftp_login = ftp_login($ftp, 'FTP賬戶', 'FTP密碼');
if($ftp && $ftp_login){
$log .= date('Y-m-d H:i:s') . " Connected to FTP Server Success\n";
}else{
$log .= date('Y-m-d H:i:s') . " Connected to FTP Server False\n";
$log .= date('Y-m-d H:i:s') . " UPDATE FALSE\n";
$log .= date('Y-m-d H:i:s') . " QUIT UPDATE\n\n";
return false;
}
$result = true;
foreach($update_list as $file_cmd){
if(substr($file_cmd, 0, 6) == 'Update') continue; //這裏有最後一行的 Update Reversion NNN 要忽略
$file_cmd = trim($file_cmd);
$cmd = substr($file_cmd, 0, 1);
$file = trim(substr($file_cmd, 1));
$from = $file;
$file = substr($file, strlen($TMP_UPDATE_DIR) + 1); //去掉路徑中的開頭 $TMP_UPDATE_DIR 路徑
$filename = is_dir($from) ? null : array_pop(explode('/', $file));
$to = $ftp_root_dir . str_replace("\\", "/", $file);
//計算出路徑並創建FTP目錄 (如果不存在的話)
$dir = is_dir($from) ? $to : dirname($to);
if(!@ftp_chdir($ftp,$dir)){
$log .= date('Y-m-d H:i:s') . " FTP_MKD\t{$dir}\n";
ftp_create_dir($dir); //創建目錄
}
if(is_dir($from)) continue;
//更新或創建文件
if($cmd == "U" || $cmd == "A"){
$result = $result && ftp_put($ftp, $to, $from, FTP_BINARY);
//記錄日志
$log .= date('Y-m-d H:i:s') . " FTP_PUT\t{$from}\t{$to}" . ($result ? "\tSUCCESS\n" : "\tFALSE\n");
//刪除文件或目錄
}else if($cmd == "D"){
//-------------------------------
// 這裏要判斷目標是目錄還是文件
//-------------------------------
if(@ftp_chdir($ftp,$to)){
$r = ftp_rmdirr($ftp, $to);
$log .= date('Y-m-d H:i:s') . " FTP_RMD\t{$to}" . ($r ? "\tSUCCESS\n" : "\tFALSE\n");
}else{
$result = $result && ftp_delete($ftp, $to);
//記錄日志
$log .= date('Y-m-d H:i:s') . " FTP_DEL\t{$to}" . ($result ? "\tSUCCESS\n" : "\tFALSE\n");
}
}else{
$log .= date('Y-m-d H:i:s') . " UNKNOWN CMD\t{$cmd}\n";
continue;
}
}
//記錄最後一次更新成功的版本
if($result){
$log .= date('Y-m-d H:i:s') . " UPDATE SUCCESS\n";
}else{
$log .= date('Y-m-d H:i:s') . " UPDATE FALSE\n";
}
$log .= date('Y-m-d H:i:s') . " END UPDATE\n\n";
file_put_contents($ftp_update_logfile, $log, FILE_APPEND);
return $result;
}
//-----------------------------
// 判斷並執行同步更新
//-----------------------------
//取得當前更新者帳戶名,判斷是否有權限更新到運行服務器
$author_name = $author[count($author) -1];
if(in_array($author_name, $upto_run_managers)){
//查看log中是否包含 [UPTO_RUN_SERVER] 指令標記
if(strpos(implode("\n", $log), '[UPTO_RUN_SERVER]') !== false){
//-------------------------------------------
// 准備開始同步更新在線服務器上的文件
//-------------------------------------------
$new_rev = $argv[2];
if(!file_exists($update_status_file)){
file_put_contents($update_status_file, '1|1');
}
$update_status = explode('|', file_get_contents($update_status_file));
//當記錄的更新狀態為更新成功的版本號{$update_status[0]} 比最後一次更新的版本號 {$update_status[1]} 小時
//還原臨時更新目錄到最後一次更新成功的版本 {$update_status[0]},然後再 update 獲得更新文件列表
//然後提交到在線服務器
if($update_status[0] < $update_status[1]){
$svn_update_r = "\"C:\\Program Files\\VisualSVN Server\\bin\\svn.exe\" update -r {$update_status[0]} {$TMP_UPDATE_DIR}";
exec($svn_update_r);
}
$output = array();
exec($svn_update, $output);
$update = $output;
//這裏根據update列表更新服務器上的文件
$update_success = true;
$update_success = update_to_ftp($update);
//記錄更新後的更新狀態到到文件
if($update_success){
file_put_contents($update_status_file, "{$new_rev}|{$new_rev}");
}else{
file_put_contents($update_status_file, "{$update_status[0]}|{$new_rev}");
}
}
}
?>
[/php]
- Sep 04 Sat 2010 15:47
團隊開發配合SVN HOOKS同步更新在線服務器源碼
全站熱搜
留言列表
發表留言