#!/bin/php
<?php
date_default_timezone_set("Europe/Berlin");
get_update_ebuilds();

function get_update_ebuilds(){
    // --autounmask-backtrack=y: necessary to print ebuilds, if useflag changes outstanding
    $exec = shell_exec("emerge --update --deep --newuse --autounmask --autounmask-continue --with-bdeps=y -pv @world 2>&1");

    
    $ebuilds = find_ebuilds($exec);
    if(count($ebuilds)==0){
        echo "no ebuilds found... try again with additional selection commands...\r\n";
        $exec2 = shell_exec("emerge --update --deep --newuse --autounmask --autounmask-continue --with-bdeps=n -pv @world 2>&1");
        $exec3 = shell_exec("emerge --update --deep --newuse --autounmask --autounmask-continue --with-bdeps=n --rebuilt-binaries -pv @world 2>&1");
        $exec4 = shell_exec("emerge --update --deep --newuse -pv @world 2>&1");
        $ebuilds = find_ebuilds($exec.$exec2.$exec3.$exec4);
    }
    if(count($ebuilds)>0){
	$buildarr = create_build_arr($ebuilds);
	echo "Found the following ebuilds to be compiled by buildhost:\r\n";
	foreach($buildarr["builds"] as $pkg=>$useflags){
	    $flags="none";
	    if(count($useflags)>0){
		$flags=join(", ",$useflags);
		if(strlen($flags)>50){
		    $flags=substr($flags,0,47)."...";
		}
	    }
	    echo "- ".$pkg." (USE-Flags: ".$flags.")\r\n";
	}
	echo "\r\n";
	
	$binrepos = find_binhost();
	echo "Build Hosts: ".join(", ",$binrepos)."\r\n";

	$rev = get_rev();
	echo "Build for rev: ".$rev."\r\n";

	$profile = get_profile();
	echo "Profile: ".$profile."\r\n";

	$world = get_world();
	echo "World: ".join(", ",$world)."\r\n";
	echo "\r\n";

    global $argv;
    if(in_array("debug",$argv)){
    	echo "DEBUG Manual compile command:\r\n";
    	foreach($buildarr["emerge_str"] as $cmd){
    	    echo $cmd."\r\n";
    	}
    	echo "\r\n";
    }
	
	if(count($binrepos)<1) die("No BINREPO configured :(\r\n");
	if(count($binrepos)>1) die("More than ONE BINREPO configured :(\r\n");
	$sendarr=array("world"=>$world,"profile"=>$profile,"rev"=>$rev,"buildarr"=>$buildarr);
	$response = send_cmd_to_server($binrepos[0],"add_task",$sendarr);
	if($response["result"] && $response["info"]["http_code"]==200 && is_array($response["data"]) && $response["data"]["code"]=="success" && $response["data"]["answer"]["did"]=="queued"){
	    $assigned_server_id=$response["data"]["answer"]["id"];
	    echo "Task is queued on buildhost! (ID: ".$assigned_server_id.")\r\n";
	    $laststatelen=0;
	    while(true){
		$response = send_cmd_to_server($binrepos[0],"check_status",array("id"=>$assigned_server_id));
		if($response["result"] && $response["info"]["http_code"]==200 && is_array($response["data"]) && $response["data"]["code"]=="success" && isset($response["data"]["answer"]["state"])){
		    echo "\r".date("d.m.Y H:i:s")." State: ".$response["data"]["answer"]["state"];
		    if((strlen($response["data"]["answer"]["state"])-$laststatelen)<0){
			$minimize = $laststatelen-strlen($response["data"]["answer"]["state"]);
			for($i=0;$i<$minimize;$i++)echo " ";
		    }
		    $laststatelen=strlen($response["data"]["answer"]["state"]);
            if(isset($response["data"]["answer"]["pkgdone"]) && is_array($response["data"]["answer"]["pkgdone"]) && in_array("all_done",$response["data"]["answer"]["pkgdone"])){
                echo "\r\n";
                echo "All ebuilds are now compiled on buildhost, todos done :)\r\n";
                exit(6);
            }
		    sleep(5);
		}
		elseif($response["result"] && $response["info"]["http_code"]==200 && is_array($response["data"]) && $response["data"]["code"]=="success" && $response["data"]["answer"]=="id state currently unavailable"){
		    $state="server did not know current state, wait...";
		    echo "\r".date("d.m.Y H:i:s")." State: ".$state;
		    if((strlen($state)-$laststatelen)<0){
			$minimize = $laststatelen-strlen($state);
			for($i=0;$i<$minimize;$i++)echo " ";
		    }
		    $laststatelen=strlen($state);
		    sleep(5);
		}
		else{
		    echo "\r\nInvalid Server Answer on check_status:\r\n";
		    print_r($response);
		    exit(1);
		}
	    }
	}
	else{
	    echo "Invalid Server Answer on add_task:\r\n";
	    print_r($response);
	    exit(1);
	}
	
	
	exit(0);
    }
    else{
	echo "All ebuilds are compiled on buildhost, nothing todo :)\r\n";
	exit(5);
    }
}
function send_cmd_to_server($server,$func,$dataarr){    
    $server = str_replace("http://","https://",$server);
    $url=$server."/../buildhost/index.php";

    $data=serialize($dataarr);
    $data=base64_encode($data);
    $postfields = http_build_query(array("func"=>$func,"data"=>$data));

    $ch = curl_init();
    curl_setopt($ch,CURLOPT_URL, $url);
    curl_setopt($ch,CURLOPT_POST, 1);
    curl_setopt($ch,CURLOPT_POSTFIELDS, $postfields);

    ob_start();
    $result = curl_exec($ch);
    $content = ob_get_contents();
    ob_end_clean();

    $info = curl_getinfo($ch);
    $data = @unserialize($content);

    curl_close($ch);
    $retarr=array("result"=>$result,"info"=>$info,"content"=>$content,"data"=>$data);
    return($retarr);
}
function find_binhost(){
    $exec = shell_exec("emerge --info 2>&1");
    $exec = explode("\n",$exec);

    $binrepos=array();
    $in_bincat=false;
    $emptyline=0;
    foreach($exec as $line){
	$line = trim($line);
	if(stripos($line,"Binary Repositories")!==false){
	    $in_bincat=true;
	}
	if($in_bincat && empty($line)){
	    $emptyline++;
	}
	if($in_bincat && substr($line,0,8)=="sync-uri"){
	    $binrepos[]=substr($line,10);
	    $emptyline=0;
	}
	if($emptyline>0 && stripos($line,"=")!==false){
	    $in_bincat=false;
	}
    }
    return($binrepos);
}

function create_build_arr($ebuilds){
    $builds=array();
    $buildstrs=array();
    foreach($ebuilds as $ebuild){
	$exp = explode("]",$ebuild);
	$prog = trim($exp[1]);
	$progs = explode(" ",$prog);
	$prog = $progs[0];
	
	unset($exp[0]);
	unset($exp[1]);
	
	$flags = $progs;
	unset($flags[0]);
	$flags=join(" ",$flags)."]".join("]",$exp);
	$flags = split_after_space($flags);
	$useflags=array();
	foreach($flags as $cat=>$flagarr){
	    foreach($flagarr as $flag){
		$flag = str_replace("(","",$flag);
		$flag = str_replace(")","",$flag);
		if(substr($cat,-1)=="=") $cat=substr($cat,0,-1);
		if(substr($flag,-1)=="%") $flag=substr($flag,0,-1);
		if(substr($flag,-1)=="*") $flag=substr($flag,0,-1);
		if($cat=="USE"){
		    $useflags[]=$flag;
		}
		else{
                    if(substr($flag,0,1)=="-"){
                        $useflags[]="-".strtolower($cat)."_".substr($flag,1);
                    }
                    else{
                        $useflags[]=strtolower($cat)."_".$flag;
                    }

		}
	    }
	}
    
    $buildstr="USE=\"".join(" ",$useflags)."\" emerge --buildpkgonly =".$prog;
	$builds[$prog]=$useflags;
	$buildstrs[]=$buildstr;
    }
    return(array("emerge_str"=>$buildstrs,"builds"=>$builds));
}
function split_after_space($flags){
    $buf_group="";
    $buf_flag="";

    $ret_flags=array();

    $in_str=false;
    $in_bracked=false;
    //echo "Search Useflags for: ".$flags.":\r\n";
    for($i=0;$i<strlen($flags);$i++){
	$char = substr($flags,$i,1);
	if($char=="[" && !$in_bracked){
	    $in_bracked=true;
	    continue;
	}
	elseif($char=="]" && $in_bracked){
	    $in_bracked=false;
	    continue;
	}
	elseif($in_bracked){
	    continue;
	}
	if($char=="\""){
	    if($in_str){
		$in_str=false;
		$ret_flags[$buf_group][]=$buf_flag;
		$buf_group="";
		$buf_flag="";
	    }
	    else{
		$in_str=true;
	    }
	    continue;
	}
	if($char==" " && $in_str){
	    $ret_flags[$buf_group][]=$buf_flag;
	    $buf_flag="";
	}
	if($char==" "){
	    continue;
	}
	
	if($in_str){
	    $buf_flag.=$char;
	}
	else{
	    $buf_group.=$char;
	}
    }
    //print_r($ret_flags);
    //echo "\r\n";
    return($ret_flags);
}


function find_ebuilds($txt){
    $ebuilds=array();
    $txt = explode("\n",$txt);
    foreach($txt as $line){
        if(substr($line,0,7)=="[ebuild"){
	    $ebuilds[]=trim($line);
	}
    }
    return($ebuilds);
}

function get_rev()
{
    $dir = opendir("/var/db/repos");
    $svnrevmin = -1;
    $svnrevmax = -1;
    while ($file = readdir($dir)) {
        if ($file == "." || $file == "..") continue;
        if(!file_exists("/var/db/repos/" . $file . "/.svn")) continue;
        $exec = shell_exec("svn info /var/db/repos/" . $file . "/ | grep \"Revision:\" | awk '{print $2}'");
        $rev = (int)$exec;
        if ($rev < $svnrevmin || $svnrevmin == -1) $svnrevmin = $rev;
        if ($rev > $svnrevmax || $svnrevmax == -1) $svnrevmax = $rev;
    }
    closedir($dir);
    if ($svnrevmin != $svnrevmax) {
        echo "SVN Revisions on different states: " . $svnrevmin . " - " . $svnrevmax . " :(\r\n";
        exit;
    }
    return ($svnrevmin);
}
function get_profile(){
    $exec = shell_exec("eselect profile show");
    $exec = explode("\n",$exec);
    foreach($exec as $line){
	if(substr($line,0,1)==" "){
	    return(trim($line));
	}
    }
    echo "No profile selection found :(\r\n";
    exit;
}
function get_world(){
    $file = file_get_contents("/var/lib/portage/world");
    $file = explode("\n",$file);
    $pkgs=array();
    foreach($file as $line){
	$line = trim($line);
	if(empty($line)) continue;
	$pkgs[]=$line;
    }
    return($pkgs);
}

