#!/usr/bin/env perl
##
## CopyRight:	HangZhou Hikvision Technology Co., Ltd. All	Right Reserved.
## FileName:	svn-commit.pl
## Author:		钱海远
## Last Update:		2015-04-16
## Contact:		qianhaiyuan@hikvision.com.cn
##
BEGIN {
  if ( $] >= 5.006_000)
    { require warnings; import warnings; }
  else
    { $^W = 1; }
}

use Encode;
use SOAP::Lite;
use Encode::CN;
use URI::Escape;
use JSON;
use Data::Dumper;
use Digest::MD5;
use Digest::MD5 qw(md5_hex);
use strict;
use Carp;
my $ver = '2.2.0';
my $svn = '/usr/local/bin/svn-org';
my $webservice='http://cm.hikvision.com.cn/webservice/GetInfo.wsdl';
my $no_user_err='GetSvnUser Failed : (Error Code 404) 系统无法定位你当前登录的SVN账户，请在SVN中保存SVN用户名后重试，如有其他疑问，请联系对应的配置管理工程师！'."\n";
my $svnroot;
my $SvnMessage;
my $repos;
my $rev;
my $line;
my $username;
my $count_coms = 0;
my @component_number;
my @component_name;

my $URL;
my @ARG_New;

if(! @ARGV)
{
	exec($svn) or die "";
	exit ;
}

my $worktype=shift @ARGV;

if ($worktype eq "ci"  || $worktype eq "commit" )
{
	while (@ARGV)
	{
		my $arg = shift @ARGV;
		if ($arg =~ /^-/)
		{
			if ($arg eq '-q' || $arg eq '--quiet' || $arg eq '-N' || $arg eq '--non-recursive' || $arg eq '--no-unlock'  || $arg eq '--force-log' || $arg eq '--keep-changelists' || $arg eq '--no-auth-cache' || $arg eq '--non-interactive' || $arg eq '--trust-server-cert' )
			{
				##直接忽略
				push(@ARG_New, $arg);
				next;
			}
			elsif($arg eq '--depth' || $arg eq '--targets' || $arg eq '-F' || $arg eq '--file' || $arg eq '--editor-cmd' || $arg eq '--encoding' || $arg eq '--with-revprop'  || $arg eq '--encoding' || $arg eq '--username' || $arg eq '--password' || $arg eq '--config-dir' || $arg eq '--config-option' )
			{
				##直接过来下一个参数
				push(@ARG_New, $arg);
				push(@ARG_New, shift @ARGV);
			}
			elsif($arg eq '--changelist' || $arg eq '--cl')
			{
				##只提交
				push(@ARG_New, $arg);
				push(@ARG_New, shift @ARGV);
				next;
			}
			elsif($arg eq '-m' || $arg eq '--message')
			{
				##日志，记录，如果有选择项目，需要修改该参数
				##push(@ARG_New, $arg);
				$SvnMessage = shift @ARGV;
				next;
			}
			elsif($arg eq '-h' || $arg eq '--help')
			{
				push(@ARG_New, $arg);
				exec($svn,$worktype,@ARG_New ) or die "";	
				exit ;
			}
			else
			{
				die "$0: `$arg' 错误的参数.\n";
			}
		}
		else
		{
			if (! defined $svnroot)
			{
				$svnroot = $arg;
				#push(@ARG_New, $arg);
			}
			else
			{
				push(@ARG_New, $arg);
			}
		}
	}
	if (! defined $svnroot) { $svnroot = '.'; }
	
	if (! defined $SvnMessage) 
	{
		 die "$0: 日志不能为空，请认真填写日志.\n";
	}

	##SVN 提交，开始调度接口并获取项目数据	
	my ($status, @out_lines) = &safe_read_from_pipe( $svn , 'info' , $svnroot);		
	if ($status){die "$0: `@_' failed with this output:@out_lines";	}

	foreach $line (@out_lines)
	{
			if ( $line =~ m/URL: / )
			{
				$line =~ s/URL: //;
				$repos = $line;
				last;
			}
	}
	$repos or die "无法获取版本库信息.";
	
	my $service = SOAP::Lite
		-> service($webservice);
	
	if ( $service->isUrlNeedProjectInfo($repos) eq 'no'  )
	{
		exec($svn,$worktype,$svnroot,@ARG_New,'-m',$SvnMessage ) or die "";	
		exit ;
	}
	
	my @repos_info=split(/\//,$repos);
	my $hash=md5_hex("<https://$repos_info[2]:443> SVN-$repos_info[3]");
	
	if(! -e $ENV{"HOME"}."/.subversion/auth/svn.simple/".$hash)
	{
		 $hash=md5_hex("<https://$repos_info[2]:443> $repos_info[3]");
		 if(! -e $ENV{"HOME"}."/.subversion/auth/svn.simple/".$hash)
		 {
			  die $no_user_err;
		 }
	}
	my $n = 2;

	open(FILE,"<",$ENV{"HOME"}."/.subversion/auth/svn.simple/".$hash)|| die $no_user_err;
	while ($line=<FILE>){
		if ( $line =~ m/username/ )	{ $n--; next; }
			if ( $n eq 0 ) { $username=$line;	last;	}
			if ( $n lt 2 ) { $n--; }
	}
	close FILE;
	
	if(! defined $username) { die $no_user_err; }
	$username =~ s/\n//g;

	my $projects=$service->getProjectList($username,"{\"ver\":\"".$ver."\"}");
	
	my $json = new JSON;
	my $decoded_json = $json->decode($projects);
	my $key;
	my $value;
	my @project;
	my @projectname;
	my $num;
	my $codereuse;
	$n = 0;
	print "请选择你的项目:\n序号  项目         => 项目名称\n\n";
	while (($key, $value) = each %{$decoded_json}) {
		  if($key ne 'None')
		  {
				  push(@project,$key);
				  push(@projectname,uri_unescape($value));
				  print "$n. $key => ".uri_unescape($value)."\n";
					$n++;
		  }
	}
	push(@project,"None");
	push(@projectname,"无项目关联");
	print "$n. None            => 无项目关联\n";
	
	print "\n";
	print "请输入你本次提交关联的项目序号:";
	while(1){
		  $num = <STDIN>;
		  $num =~ s/\n//g;
			if($num =~ /^\d+$/  &&  $project[$num] ){last;}		
			print "序号必须为一个有效数字，请重新输入你本次提交关联的项目序号:";
	}
	
	my $component_str=$service->getProjectComsList($project[$num]);
	my $num_coms = -1;
	if($component_str ne '[]' && $component_str ne '{"none":"None."}' )
	{
			$decoded_json = $json->decode($component_str);
			print "\n请输入本次提交的模块：\n";
			&read_coms_from_json($decoded_json,"");
			while(1){
				  $num_coms = <STDIN>;
				  $num_coms =~ s/\n//g;
					if($num_coms =~ /^\d+$/  &&  $component_number[$num_coms]  ){last;}		
					print "序号必须为一个有效数字，请重新输入你本次提交关联的组件:";
			}
	}

	print "\n请输入本次提交代码复用的百分比[0-100]:";
	while(1){
		$codereuse = <STDIN>;
		$codereuse =~ s/\n//g;
		if(  $codereuse =~ qr/^[1-9]\d$/ || $codereuse =~ qr/^\d$/ || $codereuse eq '100' ){last;}		
		print '复用比必须为0-100的数字，请重新输入本次提交代码复用的百分比:';
	}
	$SvnMessage .=  "\r\n#Project(".$project[$num].":".$projectname[$num].")\r\n#".($num_coms >= 0 ? ("Component(".$component_number[$num_coms].":".$component_name[$num_coms].")\r\n#") : "")."CodeReuse($codereuse)";
	if(@ARG_New)
	{
		exec($svn,$worktype,$svnroot,@ARG_New,'-m',$SvnMessage, '--with-revprop', "hik:project=".$project[$num],'--with-revprop', "hik:codereuse=".$codereuse, '--with-revprop', "hik:component=".($num_coms >= 0 ? $component_number[$num_coms] : "" )) or die "";	
	}
	else
	{
		exec($svn,$worktype,$svnroot,'-m',$SvnMessage, '--with-revprop', "hik:project=".$project[$num],'--with-revprop', "hik:codereuse=".$codereuse, '--with-revprop', "hik:component=".($num_coms >= 0 ? $component_number[$num_coms] : "" ) ) or die "";	
	}
}
else
{
	exec($svn,$worktype,@ARGV) or die "";
    exit ;
}
			
exit; 

sub read_coms_from_json
{
	my $key;
	my $value;
	my($coms_list, $father_nodes) = @_;
	if(%{$coms_list})
	{
		while (($key, $value) = each %{$coms_list})
		{	
			if ( ref($value) eq "HASH" ) {
				read_coms_from_json($value,$father_nodes."/".uri_unescape($key));
			}
			else
			{
				print "$count_coms. ".$father_nodes."/".uri_unescape($value)."\n";						
				push(@component_number,$key);
				push(@component_name,uri_unescape($value));
				$count_coms ++;
			}
		}
	}
}

sub safe_read_from_pipe
{
  unless (@_)
    {
      croak "$0: safe_read_from_pipe passed no arguments.\n";
    }

  my $pid = open(SAFE_READ, '-|');
  unless (defined $pid)
    {
      die "$0: cannot fork: $!\n";
    }
  unless ($pid)
    {
      open(STDERR, ">&STDOUT")
        or die "$0: cannot dup STDOUT: $!\n";
      exec(@_)
        or die "$0: cannot exec `@_': $!\n";
    }
  my @output;
  while (<SAFE_READ>)
    {
      s/[\r\n]+$//;
  push(@output, $_);
    }
  close(SAFE_READ);
  my $result = $?;
  my $exit   = $result >> 8;
  my $signal = $result & 127;
  my $cd     = $result & 128 ? "with core dump" : "";
  if ($signal or $cd)
    {
      warn "$0: pipe from `@_' failed $cd: exit=$exit signal=$signal\n";
    }
  if (wantarray)
    {
      return ($result, @output);
    }
  else
    {
      return $result;
    }
}

sub read_from_process
{
  unless (@_)
    {
      croak "$0: read_from_process passed no arguments.\n";
    }
  my ($status, @output) = &safe_read_from_pipe(@_);
  if ($status)
    {
      return ("$0: `@_' failed with this output:", @output);
    }
  else
    {
      return @output;
    }
}
