Gitweb增加增量更新功能
很久以前开发的功能,在服务器上执行,因为Git对utf-8支持的问题,走了很多弯路,放出所有代码供大家参考:
View Code
1 #fei add for dl_patch download 2 3 4 ############# some tools for pretty codes ######### 5 sub git_write_xml_file 6 { 7 git_header_html(); 8 my $zipfile = $file_name ;#from paramter 9 my $xmlfilename = "diff.xml"; 10 $xmlfilename = "data.$pversion.xml" if( $zipfile=~ m/pages|Documents/ ); 11 12 my $xmlfilepath = ($zipfile=~m/(.*\/)(.*).zip/ ? $1 : "").$xmlfilename; 13 # now , we open the diff.xml again to fill the md5 of the zip file 14 # by the way,we check the whether the zip file is pages,or documents 15 if( -e $xmlfilepath && $zipfile ) 16 { 17 my $md5 = file_md5_hex($zipfile); 18 $md5 = uc($md5); 19 #print "<p>$zipfile MD5: $md5</p>"; 20 my $parser = new XML::DOM::Parser ; 21 my $doc = $parser->parsefile($xmlfilepath,ProtocolEncoding => 'UTF-8'); 22 my $root = $doc->getElementsByTagName("update")->[0]; 23 my $url = $doc->getElementsByTagName("url")->[-1]; 24 my $item = $doc->getElementsByTagName("item")->[-1]; 25 my $tmp_url = $doc->getElementsByTagName("url")->[-2]; 26 # 27 if( defined($tmp_url) && $tmp_url->getAttribute("md5") eq "" ) 28 { 29 $tmp_url->setAttribute("md5",$md5); 30 } 31 else 32 { 33 $url->setAttribute("md5",$md5); 34 } 35 #write the file again 36 my $xml = ($doc->createXMLDecl('1.0')->toString).($root->toString); 37 open my $myfd, " > $xmlfilepath "; 38 print $myfd $xml ; 39 close $myfd ; 40 41 print_links($xmlfilepath,$xmlfilename); 42 43 } 44 git_footer_html(); 45 } 46 47 sub get_timestamp 48 { 49 my($sec,$min,$hour,$day,$mon,$year) = (localtime(time)); 50 $mon +=1 ; 51 $day = ($day < 10 )?"0$day":$day; 52 $mon = ($mon < 10 )?"0$mon":$mon; 53 54 return "$mon$day$hour$min" ; 55 } 56 57 #打包文件所在路径,例如kingdom.pak 58 sub get_project_path 59 { 60 my $projectName = ( $project =~ m/(.*).git/) ? $1 : ""; 61 # $projectName =~ s#(\.?)#\.pak/# ; 62 my @project_array = split( /\./ , $projectName ); 63 my ($pak_path,$p_path) ; 64 65 foreach my $folder (@project_array) 66 { 67 $p_path .= $folder."/" ; 68 } 69 $hometouchProjectRoot = $hometouchRoot.$p_path; 70 71 $project_array[0] .= ".pak" ; 72 foreach my $folder (@project_array) 73 { 74 $pak_path .= $folder."/" ; 75 } 76 $hometouchPakRoot = $hometouchRoot.$pak_path ; 77 } 78 79 #write the whole xml file 80 #input : filepath 81 # check if file esist 82 sub write_xml_file 83 { 84 my ( $xmlfilepath , $zipfile , $del_array ) = @_ ; 85 #print @$del_array; 86 my $version = 0 ; 87 my $newItem ; 88 my $doc ; 89 my $root ; 90 if( -e $xmlfilepath ) 91 { 92 my $parser = new XML::DOM::Parser ; 93 #print "xml file existed , now adding update node to it...<br />"; 94 $doc = $parser->parsefile($xmlfilepath); 95 my $item = $doc->getElementsByTagName("item")->[-1]; 96 $version = $item->getAttributeNode("version")->getValue; 97 #print $version ; 98 $root = $doc->getElementsByTagName("update")->[0]; 99 $newItem = $doc->createElement("item"); 100 } 101 else 102 { 103 #print "writing first xml..."; 104 #if file doesn't exist, create one 105 $doc = new XML::DOM::Document ; 106 $root = $doc->createElement("update"); 107 $newItem = $doc->createElement("item"); 108 } 109 110 $root->appendChild($newItem); 111 $newItem->setAttribute("version",$version+1); 112 $newItem->setAttribute("descript","update at:".get_timestamp); 113 $newItem->setAttribute("clear","0"); 114 115 $newItem->setAttribute("target","1"); 116 $newItem->setAttribute("target","0") if($zipfile =~/Documents/) ; 117 118 $newItem->setAttribute("data","$zipfile"); 119 120 my $url = $doc->createElement("url"); 121 $url->setAttribute("src","$zipfile",); 122 $url->setAttribute("dest","",); 123 $url->setAttribute("md5","",); 124 $url->setAttribute("depress","1",); 125 $newItem->appendChild($url); 126 if( @$del_array ) 127 { 128 foreach my $del (@$del_array) 129 { 130 my $delNode = $doc->createElement("del"); 131 $newItem->appendChild($delNode); 132 $delNode->setAttribute("file","$del"); 133 } 134 } 135 #else {print "nothing has been deleted...";} 136 my $xml = ($doc->createXMLDecl('1.0','UTF-8')->toString).($root->toString) ; 137 138 open my $myfd, " > $xmlfilepath "; 139 print $myfd $xml ; 140 close $myfd ; 141 #xml tidy 142 my $tidy_obj = XML::Tidy->new('filename' => $xmlfilepath); 143 $tidy_obj->tidy(); 144 $tidy_obj->write(); 145 146 } 147 148 #<feixiang> useless , for backup 149 sub extra_zip_cmd_for_hometouch 150 { 151 #in order to suite hometouch , we zip the file first , 152 #and then ,unzip it so that we can get in the folder , then zip it again 153 my ($fullpath , $target ) = @_ ; 154 my $goto_path = "" ; 155 if( -e $fullpath ) 156 { 157 $fullpath =~ /(.*\/)(.*\.zip)/ ; 158 #print $fullpath; 159 my $output_folder = $1; 160 my $file_name = $2 ; 161 #chdir($output_folder); 162 my $cmd = "unzip -o $file_name"; 163 $goto_path = $output_folder ; 164 qx(cd $goto_path && $cmd); 165 qx(cd $output_folder && rm -rf $file_name ); 166 #chdir("$output_folder$target"); 167 $cmd = "zip -qr ../$file_name *"; 168 $goto_path = "$output_folder$target" ; 169 qx(cd $goto_path && $cmd); 170 #chdir($output_folder); 171 $goto_path = $output_folder ; 172 qx(cd $goto_path && rm -rf $target); 173 } 174 } 175 176 #<feixiang> useless , for backup 177 sub exec_zip_cmd_old 178 { 179 my ( $fullpath , @am_array ) = @_ ; 180 my $cmd = "$GIT archive HEAD -o $fullpath @am_array"; 181 chdir($git_dir); 182 qx($cmd); 183 } 184 #由于中文UTF-8问题,转换思路。 185 #我们纯粹为了得到差异文件列表,所以,现在我们先将文件复制出来,再压缩这些文件得到差异包 186 sub exec_zip_cmd 187 { 188 #参数:$dir ->PAK根路径+version,用于得到压缩文件的绝对路径 。 189 my ( $dir ,$zipFileName , $am_array ) = @_ ; 190 #print "@$am_array"; 191 192 if( chdir($hometouchPakRoot) ) 193 { 194 my $tmp = "tmp"; 195 mkdir($tmp,0777) or die "createFolder error!" unless (-e $tmp); 196 chdir($tmp) or die "chdir error"; 197 foreach my $file (@$am_array) 198 { 199 #print "<br />file: $file <br />"; 200 copyFileToTmp($file); 201 } 202 #压缩tmp文件夹,得到压缩包 203 my $tag = "" ; 204 $tag = "pages" if( $zipFileName =~ m/^pages/ ); 205 $tag = "Documents" if( $zipFileName =~ m/^Documents/ ); 206 chdir($tag) or die "chdir error" if($tag ne ""); 207 my $cmd = "zip -r $dir$zipFileName *"; 208 qx($cmd); 209 #删除tmp文件夹内容 210 $cmd = "rm -rf *"; 211 qx($cmd); 212 } 213 } 214 #将文件复制到临时目录下,用mkpath支持创建多重目录 215 sub copyFileToTmp 216 { 217 my $fileName = shift ; 218 $fileName =~ m|(.*)/.+$| ; 219 my $subFolder = $1 ; 220 #print "$hometouchProjectRoot$fileName<br />"; 221 mkpath($subFolder) or die "createFolder error!" unless( -e $subFolder ) ; 222 if( !copy("$hometouchProjectRoot$fileName" , $subFolder) ) 223 { 224 #有一些文件无法复制,例如thumbs.db,不管它 225 #print "copy $hometouchProjectRoot$fileName error: $!<br />"; 226 }; 227 } 228 229 230 sub print_zip_links 231 { 232 my ( $link ,$zip_fullpath , $displayName ) = @_ ; 233 234 print <<"TEXT"; 235 <h1> 236 <a href="$link">$displayName</a> 237 <a style="margin:0 10px;" href="/gitweb/?p=$project;pv=$pversion;a=show_patch_xml;f=$zip_fullpath" target="_new">Generate XML File</a> 238 </h1><br /> 239 TEXT 240 241 } 242 # in order to get md5 , we hide the xml file links first , when user click zip download link , we do an action to get md5 and print xml links ; 243 sub print_links 244 { 245 my ( $link , $displayName ) = @_ ; 246 $link =~ s/home\/webftp\/// ; 247 print <<EOT; 248 <h1 class="center"> 249 Please right click <a href="$link">$displayName</a> and select "Save as" to download the file. 250 </h1> 251 252 EOT 253 254 } 255 #for all projects common codes 256 # at this step , we have got the added , modified and deleted files arrays 257 258 sub git_dl_patch_common 259 { 260 #修复多个数组传递问题,使用引用解决 261 my ( $output_folder, $zip_filename , $xml_filename , $am_array , $del_array ) = @_ ; 262 263 $output_folder=~ m/\/home\/webftp\/(.*)/; 264 my $linkUrl = "../".$1 ; 265 unless ( -e $output_folder ) 266 { 267 mkdir($output_folder, 0777) or die_error(500,"cannot create output folder,check your permission!"); 268 } 269 if( @$am_array ) 270 { 271 exec_zip_cmd( $output_folder,$zip_filename , $am_array ) ; 272 print_zip_links("$linkUrl$zip_filename","$output_folder$zip_filename",$zip_filename); 273 write_xml_file("$output_folder$xml_filename",$zip_filename,$del_array ) ; 274 }else 275 { 276 print "<h1>no update available</h1>"; 277 } 278 279 } 280 #special for hometouch projects: divide into pages and Documents 281 sub git_dl_patch_hometouch 282 { 283 $pversion = "1" if(!defined $pversion || $pversion eq ""); 284 my $timestamp = get_timestamp ; 285 my $zip_pages_name = "pages_$timestamp.zip"; 286 my $zip_Documents_name = "Documents_$timestamp.zip"; 287 my $xml_pages_name = "data.$pversion.xml" ; 288 my $xml_Documents_name = "data.$pversion.xml" ; 289 290 my $output_folder = $hometouchPakRoot.$pversion."/" ; 291 #print $output_folder ; 292 # now , check if the file existed ? 293 294 if( (-e "$output_folder$zip_pages_name") 295 && (-e "$output_folder$xml_pages_name") 296 && (-e "$output_folder$zip_Documents_name") 297 && (-e "$output_folder$xml_Documents_name") 298 ) 299 { 300 print "<h1>files existed,right click the links and select 'save as' to download...</h1>" ; 301 print_links("$output_folder$zip_pages_name",$zip_pages_name); 302 print_links("$output_folder$xml_pages_name",$xml_pages_name); 303 print_links("$output_folder$zip_Documents_name",$zip_Documents_name); 304 } 305 else{ 306 my @pages_amfiles = ( ) ; 307 my @pages_delfiles = ( ) ; 308 my @documents_amfiles = ( ); 309 my @documents_delfiles = ( ); 310 311 # now , we get the diff in two hashCode 312 my @difftree = git_diff_in2hash(); 313 314 foreach my $difftree_line (@difftree) 315 { 316 #print "<p>$difftree_line</p>"; 317 my %difftree = parse_difftree_raw_line($difftree_line); 318 my $file = esc_path($difftree{'to_file'}) ; 319 #print "file: $file"; 320 my $file_status = $difftree{'status'}; 321 #print "file: $file ++++ status: $file_status <br />"; 322 323 if( $file =~ m/^pages/ ) 324 { #if is pages fils .zip into pages.zip 325 parse_amd_status($file,$file_status,\@pages_amfiles,\@pages_delfiles); 326 } 327 if( $file =~ m/Documents/ ) 328 { #if is pages fils .zip into pages.zip 329 parse_amd_status($file,$file_status,\@documents_amfiles,\@documents_delfiles); 330 } 331 } 332 #print @documents_amfiles;#<for test> 333 # use common methods for pages and Documents 334 git_dl_patch_common($output_folder,$zip_pages_name,$xml_pages_name, \@pages_amfiles,\@pages_delfiles) ; 335 #extra_zip_cmd_for_hometouch($output_folder,$zip_pages_name,"pages"); 336 git_dl_patch_common($output_folder,$zip_Documents_name,$xml_Documents_name, \@documents_amfiles,\@documents_delfiles) ; 337 #extra_zip_cmd_for_hometouch($output_folder,$zip_Documents_name,"Documents"); 338 # then every thing is OK ! 339 } 340 } 341 342 sub parse_amd_status 343 { 344 #非常奇怪的问题,am_arrya和del_array反了!!! 345 my ($file, $status ,$am_array, $del_array) = @_ ; 346 #<2012年11月14日 修正bug : 文件名中含有括号正则会出错,需要转义> 347 #$file =~ s#(\(|\)|\s)#\\$1#g; 348 349 #<2013年1月10日>对于相似度为100%(目录不同)的文件,差异文件列表竟然没有!原因是上面取文件名时索引用错了!应该是$difftree{'to_file'}而不是$difftree{'file'} 350 #并且将重命名与拷贝文件加入差异列表 351 #print "<p>$file: $status</p>"; 352 if( $status eq "A" || $status eq "M" || $status eq "R" || $status eq "C") 353 { 354 #print "add:$file++++$status<br />";#<for test> 355 push @$am_array,$file ; 356 } 357 if( $status eq "D" ) 358 { 359 #print "del:$file<br />"; 360 push @$del_array, $file ; 361 } 362 } 363 364 # for all projects 365 sub git_dl_patch_forall 366 { 367 my $timestamp = get_timestamp ; 368 my $zip_filename = $timestamp.".zip"; 369 my $xml_filename = "diff.xml" ; 370 my $output_folder = $hometouchPakRoot ; 371 my $zip_fullpath = $output_folder.$zip_filename ; 372 my $xml_fullpath = $output_folder.$xml_filename ; 373 374 if( -e $zip_fullpath && $xml_fullpath ) 375 { 376 print_links($zip_fullpath,$zip_filename) ; 377 print_links($xml_fullpath,$xml_filename) ; 378 } 379 else 380 { 381 my @difftree = git_diff_in2hash(); 382 my @am_array = () ; 383 my @del_array = () ; 384 foreach my $difftree_line (@difftree) 385 { 386 my %difftree = parse_difftree_raw_line($difftree_line); 387 my $file = esc_path($difftree{'file'}); 388 my $file_status = $difftree{'status'}; 389 390 parse_amd_status($file,$file_status,\@am_array,\@del_array); 391 392 } 393 394 #print "added file and modified files : @am_array.<br />" ; 395 git_dl_patch_common($output_folder,$zip_filename,$xml_filename,\@am_array,\@del_array); 396 } 397 398 } 399 400 401 sub git_diff_in2hash() 402 { 403 $hash_base = "HEAD" if (!$hash_base) ; 404 405 open my $fd ,"-|" , git_cmd(),"diff-tree","-r",@diff_opts,"--root",$hash_base,$hash,"--",or die_error(500,"Get Diff Status Error"); 406 407 my @difftree = map { chomp; $_ }<$fd>; 408 close $fd ; 409 return @difftree ; 410 } 411 ##It's ok here , we can run the command by qx 412 sub git_dl_patch_test 413 { 414 git_header_html(); 415 qx(cd /home/git/repositories/tmp && mkdir test); 416 git_footer_html(); 417 } 418 419 #差异函数入口 420 #事实上,只需要两个参数:工程根目录和输入路径 421 sub git_dl_patch 422 { 423 git_header_html(); 424 print << "TEXT"; 425 <div class="center"> 426 427 TEXT 428 429 get_project_path();#使用全局变量设置工程目录与打包目录 430 #print "$hometouchProjectRoot<br />$hometouchPakRoot<br />"; 431 432 if( $project =~ m/hometouch/ ) 433 { 434 git_dl_patch_hometouch(); 435 } 436 else # we do common jobs 437 { 438 git_dl_patch_forall(); 439 } 440 441 print << "TEXT"; 442 </div> 443 TEXT 444 445 git_footer_html(); 446 } 447 #fei add