From 4c327e71d0349d3f7740ce91ebb730da6cad120f Mon Sep 17 00:00:00 2001
From: hahn <axel.hahn@iml.unibe.ch>
Date: Tue, 15 Oct 2013 16:35:41 +0200
Subject: [PATCH] initial - temp checkin 5

---
 .../deployment/classes/project.class.php      | 180 +++++++++++++-----
 .../deployment/config/inc_projects_config.php |  18 +-
 .../config/sshkeys/git@gitlab.iml.unibe.ch    |  27 +++
 .../sshkeys/git@gitlab.iml.unibe.ch.pub       |   1 +
 shellscripts/gitsshwrapper.sh                 |  14 ++
 5 files changed, 188 insertions(+), 52 deletions(-)
 create mode 100644 public_html/deployment/config/sshkeys/git@gitlab.iml.unibe.ch
 create mode 100644 public_html/deployment/config/sshkeys/git@gitlab.iml.unibe.ch.pub
 create mode 100644 shellscripts/gitsshwrapper.sh

diff --git a/public_html/deployment/classes/project.class.php b/public_html/deployment/classes/project.class.php
index 54d87d1e..800388c5 100644
--- a/public_html/deployment/classes/project.class.php
+++ b/public_html/deployment/classes/project.class.php
@@ -8,13 +8,35 @@ class project {
     // ----------------------------------------------------------------------
     // CONFIG
     // ----------------------------------------------------------------------
+    
+    /**
+     * config file
+     * @var type 
+     */
+    private $_sCfgfile="../config/inc_projects_config.php";
+
+    /**
+     * configuration ($aConfig in the config file)
+     * @var array
+     */
     private $_aConfig = array();
+    
+    /**
+     * configuration of the project (= $aProjects[ID] in the config file)
+     * @var array
+     */
+    private $_aPrjConfig = array();
+    
+    /**
+     * version infos of all phases
+     * @var type 
+     */
     private $_aData = array();
-    private $_sWorkDir = false;
-    private $_sPackageDir = false;
-    private $_aPhases=array();
-    private $_sCfgfile="../config/inc_projects_config.php";
     
+    /**
+     * places of version infos in each deployment phase
+     * @var type 
+     */
     private $_aPlaces=array(
         "onhold"=>"Queue",
         "ready4deployment"=>"Repo",
@@ -46,9 +68,7 @@ class project {
      */
     private function _readConfig() {
         require($this->_sCfgfile);
-        $this->_sWorkDir = $aConfig['workDir'];
-        $this->_sPackageDir = $this->_sWorkDir.'/packages';
-        $this->_aPhases=$aConfig["phases"];
+        $this->_aConfig = $aConfig;
         return true;
     }
 
@@ -57,18 +77,30 @@ class project {
      * @return boolean
      */
     private function _verifyConfig() {
-        if (!count($this->_aConfig))
-            die("ERROR::CONFIG: no config was found.");
-        if (!$this->_sPackageDir)
+        if (!count($this->_aPrjConfig))
+            die("ERROR::CONFIG: no config was for found the project. check $aProjects in config file.");
+        
+        if (!array_key_exists("packageDir", $this->_aConfig))
+            die("ERROR::CONFIG: packagedir is not defined.");
+
+        if (!$this->_aConfig["packageDir"])
             die("ERROR::CONFIG: packagedir is not set.");
-        if (!file_exists($this->_sPackageDir))
-            die("ERROR::CONFIG: packagedir does not exist: &quot;" . $this->_sPackageDir . "&quot;.");
-        if (!array_key_exists("phases", $this->_aConfig))
-            die("ERROR::CONFIG: key &quot;phases&quot; was not found in config.<br><pre>" . print_r($this->_aConfig, true) . "</pre>");
+        
+        if (!file_exists($this->_aConfig["packageDir"]))
+            die("ERROR::CONFIG: packagedir does not exist: &quot;" . $this->_aConfig['packageDir'] . "&quot;.");
+        
+        if (!array_key_exists("phases", $this->_aPrjConfig))
+            die("ERROR::CONFIG: key &quot;phases&quot; was not found in config.<br><pre>" . print_r($this->_aPrjConfig, true) . "</pre>");
+        
         // TODO: verify ausbauen
         return true;
     }
 
+    /**
+     * execute a commandline; returns a string of output of timestamp, command, output and returncode
+     * @param string $sCommand
+     * @return string
+     */
     private function _execAndSend($sCommand){
         $sReturn='';
         $bUseHtml=$_SERVER?true:false;
@@ -82,19 +114,34 @@ class project {
         flush();
         $process = proc_open($sCommand, $descriptorspec, $pipes, realpath('./'), array());
 
-        $sReturn.="[".date("H:i:s d.m.Y")."] $sCommand";
-        $sReturn.=$bUseHtml?"<br><pre>":"\n";
+        $sReturn.="[".date("H:i:s d.m.Y")."] ";
+        $sReturn.=$bUseHtml?"<strong>$sCommand</strong>":"$sCommand";
+        $sReturn.=$bUseHtml?"<br>":"\n";
 
+        $sErrors=false;
         if (is_resource($process)) {
-            $oStatus = proc_get_status($process);
             while ($s = fgets($pipes[1])) {
                 $sReturn.=$s;
                 flush();
             }
+            while ($s = fgets($pipes[2])) {
+                $sErrors.=$s;
+                flush();
+            }
+        }
+        if ($sErrors)$sReturn.="STDERR:\n".$sErrors;
+        $oStatus = proc_get_status($process);
+        $iRc=$oStatus['exitcode'];
+        $sReturn.="[".date("H:i:s d.m.Y")."] exitcode ".$iRc;
+        if ($bUseHtml){
+            if ($iRc==0) {
+                $sReturn="<pre>".$sReturn; 
+            } else {
+                $sReturn='<pre class="error">'.$sReturn;
+            }
+            $sReturn.='</pre>';
         }
-        $sReturn.=$bUseHtml?"</pre>":"\n";
-        $sReturn.="[".date("H:i:s d.m.Y")."] finished; rc=".$oStatus['exitcode'];
-        $sReturn.=$bUseHtml?"<hr>":"\n---------\n";
+        flush();
         return $sReturn;
     }
 
@@ -102,10 +149,14 @@ class project {
     // GETTER
     // ----------------------------------------------------------------------
     
+    /**
+     * get a temp directory
+     * @return string
+     */
     private function _getTempDir(){
-        $s=$this->_sWorkDir."/build/".$this->_aConfig["fileprefix"]."_".date("Ymd-His");
+        $s=$this->_aConfig['workDir']."/build/".$this->_aPrjConfig["fileprefix"]."_".date("Ymd-His");
         // TODO: auskommentieren
-        $s=$this->_sWorkDir."/build/".$this->_aConfig["fileprefix"]."_temp";
+        $s=$this->_aConfig['workDir']."/build/".$this->_aPrjConfig["fileprefix"]."_temp";
         return $s;
     }
     /**
@@ -115,7 +166,7 @@ class project {
      * @return string
      */
     private function _getFileBase($sPhase, $sPlace){
-        if (!array_key_exists($sPhase, $this->_aPhases)){
+        if (!array_key_exists($sPhase, $this->_aConfig["phases"])){
             die("ERROR: _getFileBase - this phase does not exist: $sPhase.");
         }
         if (!array_key_exists($sPlace, $this->_aPlaces)){
@@ -124,14 +175,14 @@ class project {
         
         
         // local file for onhold|ready4deployment
-        $sBase=$this->_sPackageDir."/".$sPhase."/".$this->_aConfig["fileprefix"];
+        $sBase=$this->_aConfig['packageDir']."/".$sPhase."/".$this->_aPrjConfig["fileprefix"];
         
         if ($sPlace=="onhold") $sBase.="_onhold";
         
         // url for deployed
         if ($sPlace=="deployed"){
-            if ($this->isActivePhase($sPhase) && array_key_exists("url", $this->_aConfig["phases"][$sPhase])){
-                $sBase=$this->_aConfig["phases"][$sPhase]["url"].$this->_aConfig["fileprefix"];
+            if ($this->isActivePhase($sPhase) && array_key_exists("url", $this->_aPrjConfig["phases"][$sPhase])){
+                $sBase=$this->_aPrjConfig["phases"][$sPhase]["url"].$this->_aPrjConfig["fileprefix"];
             } else {
                 $sBase='';
             }
@@ -167,7 +218,7 @@ class project {
      * @return array
      */
     public function getConfig() {
-        return $this->_aConfig;
+        return $this->_aPrjConfig;
     }
 
     /**
@@ -175,7 +226,7 @@ class project {
      * @return string
      */
     public function getLabel() {
-        return $this->_aConfig["label"];
+        return $this->_aPrjConfig["label"];
     }
 
     /**
@@ -183,7 +234,7 @@ class project {
      * @return string
      */
     public function getDescription() {
-        return $this->_aConfig["description"];
+        return $this->_aPrjConfig["description"];
     }
 
     /**
@@ -193,7 +244,7 @@ class project {
     public function getAllPhaseInfos(){
         if (!array_key_exists("phases", $this->_aData)) $this->_aData["phases"]=array();
         
-        foreach(array_keys($this->_aPhases) as $sPhase){
+        foreach(array_keys($this->_aConfig["phases"]) as $sPhase){
             if (!array_key_exists($sPhase, $this->_aData["phases"])){
                 $this->getPhaseInfos($sPhase);
             }
@@ -260,7 +311,7 @@ class project {
             $sJsonfile=$this->_getInfofile($sPhase, $sKey);
             $aTmp[$sKey]=array();
             if ($this->isActivePhase($sPhase)){
-                $sJsonUrl=$this->_aConfig["phases"][$sPhase]["url"].$this->_aConfig["fileprefix"].".json";
+                $sJsonUrl=$this->_aPrjConfig["phases"][$sPhase]["url"].$this->_aPrjConfig["fileprefix"].".json";
                 $sJsonData=@file_get_contents($sJsonUrl);
                 if ($sJsonData){
                     $aJson=json_decode($sJsonData, true);
@@ -291,9 +342,9 @@ class project {
      */
     public function isActivePhase($sPhase){
         return (
-                array_key_exists($sPhase, $this->_aConfig["phases"])
-                && array_key_exists("url", $this->_aConfig["phases"][$sPhase])
-                && $this->_aConfig["phases"][$sPhase]["url"]
+                array_key_exists($sPhase, $this->_aPrjConfig["phases"])
+                && array_key_exists("url", $this->_aPrjConfig["phases"][$sPhase])
+                && $this->_aPrjConfig["phases"][$sPhase]["url"]
             );
     }
 
@@ -303,14 +354,14 @@ class project {
      */
     public function getNextPhase($sPhase=false){
         if ($sPhase){
-            if (!array_key_exists($sPhase, $this->_aPhases)){
+            if (!array_key_exists($sPhase, $this->_aConfig["phases"])){
                 die("ERROR: this phase does not exist: $sPhase.");
             }
         }
         
         $sNextPhase=false;
         $bUseNextPhase=$sPhase?false:true;
-        foreach(array_keys($this->_aPhases) as $s){
+        foreach(array_keys($this->_aConfig["phases"]) as $s){
             if ($bUseNextPhase){
                 if ($this->isActivePhase($s)){
                     $sNextPhase=$s;
@@ -338,7 +389,7 @@ class project {
         }
         
         
-        if (!array_key_exists($sPhase, $this->_aPhases)){
+        if (!array_key_exists($sPhase, $this->_aConfig["phases"])){
             die("ERROR: in canDeploy this phase does not exist: $sPhase.");
         }
         if (!$this->isActivePhase($sPhase)){
@@ -387,12 +438,12 @@ class project {
      * @return boolean
      */
     public function setProjectById($sId) {
-        $this->_aConfig = array();
+        $this->_aPrjConfig = array();
         require($this->_sCfgfile);
         if (!array_key_exists("$sId", $aProjects)){
             die("ERROR: a project with ID $sId does not exist.");
         }
-        $this->_aConfig=$aProjects[$sId];
+        $this->_aPrjConfig=$aProjects[$sId];
         $_aConfig["id"]=$sId;
         $this->_verifyConfig();
         return true;
@@ -404,20 +455,55 @@ class project {
     
     public function build(){
         $sReturn=false;
-        switch ($this->_aConfig["build"]["type"]) {
+        switch ($this->_aPrjConfig["build"]["type"]) {
             case "git":
                 
                 $sTempDir=$this->_getTempDir();
                 $sFirstLevel=$this->getNextPhase();
                 
-                // $this->_execAndSend($sCommand);
-                $sReturn.="TODO:<br>";
-                @mkdir($sTempDir);
+                // --- checkout
+                $sReturn.="<h3>Checkout</h3>";
+                if (!file_exists($sTempDir)) {
+                    $sReturn.="* create ".$sTempDir."<br>";
+                    mkdir($sTempDir);
+                }
+                if (!file_exists($sTempDir)) {
+                    die("ERROR: build - $sTempDir was not created.");
+                }
+                
+                // $sReturn.=$this->_execAndSend("find " . $this->_aConfig["workDir"]);
+                $sReturn.=$this->_execAndSend("cd $sTempDir && git init");
+                
+                $sKeyfile=dirname(dirname(__file__))."/".$this->_aPrjConfig["build"]["keyfile"];
+                $sWrapper=dirname(dirname(dirname(dirname(__file__))))."/shellscripts/gitsshwrapper.sh";
+                $sReturn.=$this->_execAndSend("ls -l ".$sWrapper);
+                // $sReturn.=$this->_execAndSend("ls -l ".$sKeyfile);
+                $sReturn.=$this->_execAndSend("cd $sTempDir && export GIT_SSH=$sWrapper ; export PKEY=$sKeyfile; git pull ".$this->_aPrjConfig["build"]["ssh"]);
+                
+                $sVersion.=$this->_execAndSend("cd $sTempDir && export GIT_SSH=$sWrapper ; export PKEY=$sKeyfile; git pull ".$this->_aPrjConfig["build"]["ssh"]);
+                
+                $sReturn.=$this->_execAndSend("ls -lisa $sTempDir");
+                $sVersioninfo=shell_exec("cd $sTempDir && git log -1");
+                
+                $sReturn.=$sVersioninfo;
+
+                // --- execute hook
+                $sHookfile=$this->_aConfig['hooks']['build-aftercheckout'];
+                $sReturn.='<h3>Execute Hook '.$sHookfile.'</h3>';
+                if (file_exists($sTempDir.'/'.$sHookfile)){
+                    $sReturn.=$this->_execAndSend('cd '.$sTempDir.' && bash "'.$sHookfile .'"');
+                } else {
+                    $sReturn.='SKIP. Hook was not found.<br>';
+                }
+                
+                // --- create package
+                $sReturn.='<h3>Create package</h3>';
+                if (!file_exists($sTempDir.'/public_html')){
+                    $sReturn.='ERROR: a subdir public_html does not exist.';
+                    return $sReturn;
+                }
                 
-                $this->_execAndSend("");
                 
-                $sReturn.="* GIT PULL ".$this->_aConfig["build"]["url"]."<br>";
-                $sReturn.="* wenn Hook-Skript im Projekt, dann ausfuehren<br>";
                 $sReturn.="* Check: gibt es ein public_html - wenn nein: abbrechen<br>";
                 $sReturn.="* <br>";
                 $sReturn.="* Info-JSON erstellen und in public_html ablegen<br>";
@@ -432,7 +518,7 @@ class project {
                 break;
 
             default:
-                die("Build Type not supported: " . $this->_aConfig["build"]["type"]);
+                die("Build Type not supported: " . $this->_aPrjConfig["build"]["type"]);
                 break;
         }
         return $sReturn;
diff --git a/public_html/deployment/config/inc_projects_config.php b/public_html/deployment/config/inc_projects_config.php
index e8211095..ad59d1fd 100644
--- a/public_html/deployment/config/inc_projects_config.php
+++ b/public_html/deployment/config/inc_projects_config.php
@@ -8,7 +8,10 @@
 $aConfig=array(
     
     // Basispfad:
-    'workDir'=>"/var/imldeployment",
+    'workDir'=>'/var/imldeployment',
+    'hooks'=>array(
+        'build-aftercheckout'=>'hooks/build.sh',
+    ),
     
     
     'phases'=>array(
@@ -36,7 +39,10 @@ $aProjects=array(
 		"contact" => 'axel.hahn@iml.unibe.ch',
 		"build"=>array(
 			"type"=>"git", // one of git, svn, ...
-			"url"=>"gitlab.iml.unibe.ch:admins/imldeployment.git",
+			"ssh"=>"git@gitlab.iml.unibe.ch:admins/imldeployment.git",
+                    
+                        // der public Key muss beim Git-Repo hinterlegt sein
+			"keyfile"=>"config/sshkeys/git@gitlab.iml.unibe.ch",
                 ),
 
 		"phases"=>array(
@@ -58,7 +64,10 @@ $aProjects=array(
 		"contact" => 'Entwickler, Verantwortliche etc.',
 		"build"=>array(
 			"type"=>"git", // one of git, svn, ...
-			"url"=>"ssh gituser@gitserver:/path/to/project",
+                        // for github:
+                        // generate ssh keypair
+                        // https://help.github.com/articles/generating-ssh-keys
+			"ssh"=>"ssh gituser@gitserver:/path/to/project",
                 ),
 
 		"phases"=>array(
@@ -127,8 +136,7 @@ switch ($_SERVER["SERVER_NAME"]) {
         break;
 }
 
+
 $aConfig=array_merge($aConfig, array(
-    'builtDir'=>$aConfig['workDir'].'/built',
     'packageDir'=>$aConfig['workDir'].'/packages',
 ));
-
diff --git a/public_html/deployment/config/sshkeys/git@gitlab.iml.unibe.ch b/public_html/deployment/config/sshkeys/git@gitlab.iml.unibe.ch
new file mode 100644
index 00000000..ffe9dd74
--- /dev/null
+++ b/public_html/deployment/config/sshkeys/git@gitlab.iml.unibe.ch
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAz36Hcm+QX0lI5sm9BLy9I1HkWXtHgHDAsDYdPGkkzp5DjxHF
+QsroQqhKObl17NCIJm4B6i5ORB2mvfVXk9R/3hP24NRvfI0TSS2rU0HbHY37zKPF
+TQ4gQaDcEnafDOmy6j9PXoGgQ8PyA+LvDWmKLJZDQbHIis2aWzlb7/KUne1VHqQU
+rUKagMz0aFvvAeC25IwBmH5Lwimb6vYwbxSBqoAT7KXmruwu8LFhBDjQqaiq5c7z
+q7FkSQovJtss1mVc5/mW0SYkS8ekxjOmIY6pPswVroYEefA5b2vw2MrC5cSU0pQ5
+TdHgxmkNmy+QAWTKs7pTR/7nDGNU9y8Sc04WUQIDAQABAoIBAQCKjAIE91l/Rn/X
+Gn2L3Dquis/er+JecOs4velnnQ1mqWaS8Vq17qaHW7e0M5H6PoOqpWnB5Il+Eg50
+aI3Bt/JpZwtBtJd8ovZttoDfZunYIiYvzmq/uN7w82f/LBWnmaRNpVhp0kQg+4Vt
+8umMGxyYCP1/sCYoCIE4yGQLI/74M3z88ldTC9un5xbx5hVHucOIlx24AwSWaNAS
+IFJGOYtIyWD/3ZkI/JH1irnX71lGE0G64VLujzVZC9SpqYETKmr5xHJapYEdvltx
+w6vwjGCZV9jpsyXtHPeyYSaSmqQaK0+PL0ZpkEnZei8ulduXgcjl21Wh+bUBJhlS
+Eoqe60DBAoGBAOqRstkffnrB/1itdjtvgWT7G3WEgU/pHUUp4TzNZshBrZP65w8F
+yiy7hNxbiz+JWy1gGSJSwP4YBQPEAeY+dGiPw3wjye3gn4zIwoGrgbEShBNiOK7z
+M+L13fFyJnkFz7YS2PWv488j8NpXspY9+0KrfDw5S2jtzfNE9PpG0HbTAoGBAOJz
+lIrNfXZl9ZU4D0/mJrgEbZvO5/F/HMZbVbK6OgYmJpcaeGbtDgHqH/qsviCV4u0b
+LIRoXutugmvwYoa64YVnAPYVlhVDwOQiU3v0LUFV+mZxTDaK7kr3Na3aI4wd1J1C
+l9mbvOh8iY84+a/VZijLeG4fXbZ/ZWV8bif74I/LAoGBAOIwtOGh+Piu8We1fPk7
+QO77JTNhHsDL7amwBL3440/f5V146C4YSyhvemJy9AfEj+Nlc1chrXBYAR3seFhp
+iR764mpmqGV14OSFAuq/U0RIsotuf3JUmogUxnv4sxiofe74pbXkcixgX/Rr9I3k
+HtHfQuFf7lO0XJBkwkZE2uh5AoGBALMFMG8y2HabUDRxJxnBFubvCT/dqFuwY60k
+U3GB65Ek4+kc0gZ8bVByKGnh2kSkect8agsa/78blBuE5D8iylrN/WKN2iJhd8Ji
+qKEbfhNixxvpgZi06IF3QYZ5JxUEGCtik+1CQ2t/2LfTEQFCsQqbIE/emBVITX6X
+ifYuF29VAoGAEfxoPdtEjzsd7jxw3vnAGVAHNR2g9sklpcJnMcrkokuZjti+iE3g
+xOqkzRzfJyYSRz46VzzgDJUJWluxudDaaSXvGmVOgeFPlF2jHdsS0XfiE8NrfBD3
+36GY7UZ+grbNktguaKtCkPXuKIxtM30+1c7kZVoTQ+dnTKErCyjuU0Y=
+-----END RSA PRIVATE KEY-----
\ No newline at end of file
diff --git a/public_html/deployment/config/sshkeys/git@gitlab.iml.unibe.ch.pub b/public_html/deployment/config/sshkeys/git@gitlab.iml.unibe.ch.pub
new file mode 100644
index 00000000..2ddfb0dc
--- /dev/null
+++ b/public_html/deployment/config/sshkeys/git@gitlab.iml.unibe.ch.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDPfodyb5BfSUjmyb0EvL0jUeRZe0eAcMCwNh08aSTOnkOPEcVCyuhCqEo5uXXs0IgmbgHqLk5EHaa99VeT1H/eE/bg1G98jRNJLatTQdsdjfvMo8VNDiBBoNwSdp8M6bLqP09egaBDw/ID4u8NaYoslkNBsciKzZpbOVvv8pSd7VUepBStQpqAzPRoW+8B4LbkjAGYfkvCKZvq9jBvFIGqgBPspeau7C7wsWEEONCpqKrlzvOrsWRJCi8m2yzWZVzn+ZbRJiRLx6TGM6Yhjqk+zBWuhgR58Dlva/DYysLlxJTSlDlN0eDGaQ2bL5ABZMqzulNH/ucMY1T3LxJzThZR imldeploy
\ No newline at end of file
diff --git a/shellscripts/gitsshwrapper.sh b/shellscripts/gitsshwrapper.sh
new file mode 100644
index 00000000..201c2c9f
--- /dev/null
+++ b/shellscripts/gitsshwrapper.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+# wrapper to make git remote command with ssh private key file
+# http://alvinabad.wordpress.com/2013/03/23/how-to-specify-an-ssh-key-file-with-the-git-command/
+#
+# SYNTAX:
+# gitwrapperssh.sh [keyfile] [command]
+#
+
+if [ -z "$PKEY" ]; then
+    # if PKEY is not specified, run ssh using default keyfile
+    ssh "$@"
+else
+    ssh -i "$PKEY" "$@"
+fi
\ No newline at end of file
-- 
GitLab