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 

 

posted @ 2013-04-09 17:35  ifeixiang  阅读(1254)  评论(0编辑  收藏  举报