diff --git a/public_html/deployment/classes/project.class.php b/public_html/deployment/classes/project.class.php index 793748badd91adc1d44d108b039c4a67ab700af7..11b279872fca1edf45d01338adbc20223c4cbc2d 100644 --- a/public_html/deployment/classes/project.class.php +++ b/public_html/deployment/classes/project.class.php @@ -66,6 +66,12 @@ class project { */ private $_iRcAll = 0; + /** + * object to access a version control, .e. git + * @var type + */ + private $_oVcs = false; + // ---------------------------------------------------------------------- // constructor // ---------------------------------------------------------------------- @@ -782,68 +788,45 @@ class project { * @return array */ public function getRepoRevision($bRefresh = false) { - $sReturn = ""; + // $sReturn = ""; if ( array_key_exists("source", $this->_aData["phases"]) && $this->_aData["phases"]["source"] && $bRefresh == false ) { return $this->_aData["phases"]["source"]; } - switch ($this->_aPrjConfig["build"]["type"]) { - case "git": - - $sKeyfile = $this->_aConfig["appRootDir"] . "/" . $this->_aPrjConfig["build"]["keyfile"]; - $sWrapper = $this->_aConfig["appRootDir"] . "/shellscripts/gitsshwrapper.sh"; - - - $sTmpDir = "/tmp/checkout_" . $this->_aConfig["id"] . "/"; - $sGitCmd = "export GIT_SSH=$sWrapper ; "; - $sGitCmd.="export PKEY=$sKeyfile ; "; - if (!file_exists($sTmpDir . ".git")) { - // $sGitCmd.="set -vx ; "; - $sGitCmd.="mkdir $sTmpDir && cd $sTmpDir && "; - $sGitCmd.="git init >/dev/null && "; - $sGitCmd.="git remote add origin " . $this->_aPrjConfig["build"]["ssh"] . " && "; - } else { - $sGitCmd.="cd $sTmpDir && "; - } - $sGitCmd.="git fetch --update-head-ok 2>&1 && "; - $sGitCmd.="git log -1 origin/master ; "; - $sReturn.= shell_exec($sGitCmd); - // echo "<pre><strong>$sGitCmd</strong><br>$sReturn</pre>"; - // revision aus der Ausgabe ziehen - $sRevision = false; - if (preg_match('#commit\ (.*)#', $sReturn, $aRev)) { - $sRevision = $aRev[1]; - } - - if ($sRevision) { - $this->_aData["phases"]["source"] = array( - "revision" => $sRevision, - "message" => $sReturn - ); - } else { - if (!$sReturn) { - // $sReturn=$this->_aPrjConfig["build"]["ssh"]; - $sReturn = $sGitCmd; - } - $this->_aData["phases"]["source"] = array( - "error" => $sReturn - ); - } - - break; - case "": - $this->_aData["phases"]["source"] = array( - "error" => t("class-project-error-repo-type-not-set"), - ); - break; - default: + + if (!$this->_aPrjConfig["build"]["type"]){ + $this->_aData["phases"]["source"] = array("error" => t("class-project-error-repo-type-not-set"),); + } else { + $this->_initVcs(); + if ($this->_oVcs){ + $this->_aData["phases"]["source"] = $this->_oVcs->getRepoRevision(); + } else { $this->_aData["phases"]["source"] = array( "error" => sprintf(t("class-project-error-repo-type-not-supported"), $this->_aPrjConfig["build"]["type"]), ); + } } return $this->_aData["phases"]["source"]; } + + private function _initVcs(){ + if (!$this->_oVcs) { + if (!$this->_aPrjConfig["build"]["type"]){ + $this->_aData["phases"]["source"] = array("error" => t("class-project-error-repo-type-not-set"),); + } else { + if (!@include_once("vcs.".$this->_aPrjConfig["build"]["type"].".class.php")){ + $this->_aData["phases"]["source"] = array( + "error" => sprintf(t("class-project-error-repo-type-not-supported"), $this->_aPrjConfig["build"]["type"]), + ); + } else { + + $this->_oVcs=new vcs($this->_aPrjConfig["build"]); + } + } + } + return $this->_oVcs; + } // ---------------------------------------------------------------------- // SETTER @@ -869,6 +852,9 @@ class project { $this->_aConfig["id"] = $sId; $this->_aPrjConfig = json_decode(file_get_contents($this->_getConfigFile($sId)), true); + + // for vcs classes + $this->_aPrjConfig["build"]["appRootDir"]=$this->_aConfig["appRootDir"]; // $aData=json_decode(file_get_contents($this->_getConfigFile($sId)), true); // echo "<pre>" . print_r($aData, true) . "</pre>"; @@ -996,6 +982,13 @@ class project { $aActionList['iActive'] ++; $this->_TempFill($sReturn, $aActionList); + $this->_initVcs(); + if (!$this->_oVcs) { + $sError = sprintf(t('class-project-error-build-type-not-supported'), $this->_aPrjConfig["build"]["type"]); + $this->_logaction($sError, __FUNCTION__, "error"); + return $this->getBox("error", $sError . $sReturn); + } + // -------------------------------------------------- // create workdir // -------------------------------------------------- @@ -1025,40 +1018,21 @@ class project { // -------------------------------------------------- // checkout // -------------------------------------------------- - switch ($this->_aPrjConfig["build"]["type"]) { - case "git": - - $sReturn.='<h3>' . t('class-project-build-label-get-sources-from-version-control') . '</h3>'; - // $sReturn.=$this->_execAndSend("find " . $this->_aConfig["workDir"]); - // SKIP $sReturn.=$this->_execAndSend("cd $sTempDir && git init"); - - $sKeyfile = $this->_aConfig["appRootDir"] . "/" . $this->_aPrjConfig["build"]["keyfile"]; - $sWrapper = $this->_aConfig["appRootDir"] . "/shellscripts/gitsshwrapper.sh"; - // $sReturn.=$this->_execAndSend("cd $sTempDir && export GIT_SSH=$sWrapper ; export PKEY=$sKeyfile; git pull " . $this->_aPrjConfig["build"]["ssh"]); - $sReturn.=$this->_execAndSend("export GIT_SSH=$sWrapper ; export PKEY=$sKeyfile; git clone " . $this->_aPrjConfig["build"]["ssh"] . " $sTempDir "); - - // $sVersion=$this->_execAndSend("cd $sTempDir && export GIT_SSH=$sWrapper ; export PKEY=$sKeyfile; git pull " . $this->_aPrjConfig["build"]["ssh"]); - // control: directory listing after checkout - $sReturn.=$this->_execAndSend("ls -lisa $sTempDir"); - - // fetch version infos - - $sRevision = shell_exec("cd $sTempDir && git log -n 1 --pretty=format:\"%H\""); - $sCommitMsg = shell_exec("cd $sTempDir && git log -1"); - $sCommitMsg = str_replace("\n", "<br>", $sCommitMsg); - $sCommitMsg = str_replace('"', """, $sCommitMsg); - // $sCommitMsg = str_replace('<', "<", $sCommitMsg); - // $sCommitMsg = str_replace('>', ">", $sCommitMsg); - $sReturn.=$this->getBox("info", $sCommitMsg); - - break; + $sReturn.='<h3>' . t('class-project-build-label-get-sources-from-version-control') . '</h3>'; + + $this->_oVcs->getSources($sTempDir); + + $aVersion=$this->_oVcs->getRevision($sTempDir); + $sRevision=$aVersion["revision"]; + $sCommitMsg=$aVersion["message"]; + $sCommitMsg = str_replace("\n", "<br>", $sCommitMsg); + $sCommitMsg = str_replace('"', """, $sCommitMsg); + // $sCommitMsg = str_replace('<', "<", $sCommitMsg); + // $sCommitMsg = str_replace('>', ">", $sCommitMsg); + $sReturn.=$this->getBox("info", $sCommitMsg); + + $sReturn.=$this->_execAndSend("ls -lisa $sTempDir"); - default: - $this->_TempDelete(); - $sError = sprintf(t('class-project-error-build-type-not-supported'), $this->_aPrjConfig["build"]["type"]); - $this->_logaction($sError, __FUNCTION__, "error"); - return $this->getBox("error", $sError . $sReturn); - } if (!$this->_iRcAll == 0) { $this->_TempDelete(); $sError = sprintf(t('class-project-error-command-failed'), $sTempDir) . $sReturn; @@ -1129,11 +1103,14 @@ class project { // -------------------------------------------------- - // TODO: cleanup .git, .svn, ...? - // wenn es kein .git gibt, bricht er ab... + // cleanup .git, .svn, ... // -------------------------------------------------- $sReturn.='<h3>' . t('class-project-build-label-cleanup-project') . '</h3>'; - $sReturn.=$this->_execAndSend("cd $sTempDir && rm -rf .git"); + if ($this->_oVcs){ + $this->_oVcs->cleanupWorkdir($sTempDir); + } + + // $sReturn.=$this->_execAndSend("cd $sTempDir && rm -rf .git"); // $sReturn.=$this->_execAndSend("cd $sTempDir && rm -rf .svn"); // $sReturn.=$this->_execAndSend("find $sTempDir -type d -name '.svn' -exec rm -rf {} \;"); $aActionList['iActive'] ++; diff --git a/public_html/deployment/classes/vcs.git.class.php b/public_html/deployment/classes/vcs.git.class.php new file mode 100644 index 0000000000000000000000000000000000000000..1a4a995fe89e78a7fb811308dff98ea7fcd29798 --- /dev/null +++ b/public_html/deployment/classes/vcs.git.class.php @@ -0,0 +1,178 @@ +<?php + +require_once("vcs.interface.php"); + +/** + * version control system :: GIT + * implements vcs interface + * + * + * @author hahn + */ +class vcs implements iVcs { +// class vcs { + + private $_aCfg=array(); + private $_sTempDir= false; // temp dir to fetch repo version and ommit message + + private $_sKeyfile = false; + private $_sWrapper = false; + + public function __construct($aRepoConfig=array()) { + $this->setConfig($aRepoConfig); + } + + public function setConfig($aRepoConfig=array()){ + + // checks + foreach(array("type", "ssh") as $key){ + if (!array_key_exists($key, $aRepoConfig)){ + die("ERROR: key $key does not exist in config <pre>". print_r($aRepoConfig, true)."</pre>"); + } + if (!$aRepoConfig[$key]){ + die("ERROR: key $key in config exists but is empty<pre>". print_r($aRepoConfig, true)."</pre>"); + } + } + if ($aRepoConfig["type"]!=="git") { + die("ERROR: type is not git<pre>". print_r($aRepoConfig, true)."</pre>"); + } + + // set config array + $this->_aCfg=$aRepoConfig; + + // define temp dir + $this->_sTempDir=$this->_aCfg["ssh"]; + $this->_sTempDir=getenv("temp").'/checkout_vcsgit_'. preg_replace('/[\@\.\:\/]/', '_', $this->_sTempDir); + $this->_sKeyfile = $this->_aCfg["appRootDir"] . "/" . $this->_aCfg["keyfile"]; + $this->_sWrapper = $this->_aCfg["appRootDir"] . "/shellscripts/gitsshwrapper.sh"; + + return $this->_aCfg=$aRepoConfig; + } + + public function dump(){ + echo "<h3>Dump class ".__CLASS__."</h3>"; + echo "config array: <pre>" . print_r($this->_aCfg, true) . "</pre>"; + echo "temp dir to read revision: ".$this->_sTempDir."<br>"; + return true; + } + + /** + * cleanup unneeded files and directories in a checked out directory + * and remove all vcs specific files and directories + * @return bool + */ + public function cleanupWorkdir($sWorkDir) { + if (!is_dir($sWorkDir)) { + return false; + } + @rmdir($sWorkDir."/.git"); + @unlink($sWorkDir."/.gitignore"); + return true; + } + + /** + * return the build type, i.e. git|svn|cvs| + * @return string + */ + public function getBuildType() { + return $this->_aCfg["type"]; + } + + /** + * get current revision and log message from remote repository + * @see $this::getRevision + * @return array + */ + public function getRepoRevision() { + return $this->getRevision(false); + } + + /** + * get current revision and log message from an existing directory or a + * remote repository + * the return will fill $this->_aData["phases"]["source"] in project class + * (array keys are revision, message or error) + * if ok: + * array( + * "revision" => $sRevision, + * "message" => $sCommitmessage + * ); + * + * on error: + * array( + * "error" => $sErrormessage, + * ); + * @return array + */ + public function getRevision($sWorkDir=false) { + $aReturn=array(); + $sGitCmd = 'export GIT_SSH="'.$this->_sWrapper.'" ; export PKEY="'.$this->_sKeyfile.'" ; '; + + if ($sWorkDir){ + $sGitCmd.='cd "'.$sWorkDir.'" && '; + } else { + if (!file_exists($this->_sTempDir . ".git")) { + $sGitCmd.='mkdir "'.$this->_sTempDir.'" && cd "'.$this->_sTempDir.'" && '; + $sGitCmd.='git init >/dev/null && '; + $sGitCmd.='git remote add origin "' . $this->_aPrjConfig["build"]["ssh"] . '" && '; + } else { + $sGitCmd.='cd "'.$this->_sTempDir.'" && '; + } + $sGitCmd.='git fetch --update-head-ok 2>&1 && '; + } + + $sGitCmd.='git log -1 origin/master ; '; + $sLoginfo.= shell_exec($sGitCmd); + + $sRevision = false; + if (preg_match('#commit\ (.*)#', $sLoginfo, $aRev)) { + $sRevision = $aRev[1]; + } + + if ($sRevision) { + $aReturn = array( + "revision" => $sRevision, + "message" => $sLoginfo + ); + } else { + if (!$sLoginfo) { + $sLoginfo = $sGitCmd; + } + $aReturn = array( + "error" => $sLoginfo + ); + } + + return $aReturn; + } + + /** + * get sources from vsc and check them out in given directory + * @return bool + */ + public function getSources($sWorkDir) { + if (!$sWorkDir || !is_dir($sWorkDir)){ + return false; + } + + $sGitCmd = 'export GIT_SSH="'.$this->_sWrapper.'" ; export PKEY="'.$this->_sKeyfile.'" ; '; + $sGitCmd .= 'git clone "'.$this->getUrl().'" "'.$sWorkDir.'"; '; + + return shell_exec($sGitCmd); + } + + /** + * return url to vcs sources + */ + public function getUrl() { + return $this->_aCfg["ssh"]; + } + + /** + * return url to view sources in webrowser to generate an infolink + */ + public function getWebGuiUrl() { + return $this->_aCfg["webaccess"]; + } + +} diff --git a/public_html/deployment/classes/vcs.interface.php b/public_html/deployment/classes/vcs.interface.php new file mode 100644 index 0000000000000000000000000000000000000000..e618f7cb2b534f696de4800fa22af98053f2d073 --- /dev/null +++ b/public_html/deployment/classes/vcs.interface.php @@ -0,0 +1,59 @@ +<?php +/** + * BRAINSTORMING ONLY + * + * interface for a version control system + * @author hahn + */ +interface iVcs { + + // ---------------------------------------------------------------------- + // get metadata + // ---------------------------------------------------------------------- + + /** + * return url to vcs sources + */ + public function getUrl(); + + /** + * return url to view sources in webrowser to generate an infolink + */ + public function getWebGuiUrl(); + + /** + * return the build type, i.e. git|svn|cvs| + */ + public function getBuildType(); + + // ---------------------------------------------------------------------- + // actions + // ---------------------------------------------------------------------- + /** + * cleanup unneeded files and directories in a checked out directory + * and remove all vcs specific files and directories + * @return bool + */ + public function cleanupWorkdir($sWorkDir); + + /** + * get current revision and log message from remote repo + * @return array + */ + public function getRepoRevision(); + + /** + * get current revision and log message from given directory + * @return array + */ + public function getRevision($sWorkDir); + + /** + * get sources from vsc and check them out in given directory + * @return bool + */ + public function getSources($sWorkDir); + + +} +