X-Git-Url: http://git.pk910.de/?p=GITManagedWebpage.git;a=blobdiff_plain;f=GITManagedWebpage.class.php;h=0522cc8ea39ac14b08691be4753000d503ef912a;hp=9093b8a4e2c0795848076be94474529ae703db01;hb=544c09a8193efa6a76865150797bec1bd4fba1c1;hpb=15ab535a9925f003333ab3180c8f660d53bb66e4 diff --git a/GITManagedWebpage.class.php b/GITManagedWebpage.class.php index 9093b8a..0522cc8 100644 --- a/GITManagedWebpage.class.php +++ b/GITManagedWebpage.class.php @@ -25,31 +25,55 @@ class GITManagedWebpage { const ERROR_CRITICAL = 1; - + const SESSION_PREFIX = "GITManagedWebpage_"; private $giturl; - private $workdir; + private $workdir, $localdir; + private $ready = false; + private $loopedcall = false; + private $config = null; + private $config_changed = true; + private $activeSession = null; - public function __construct($giturl, $workdir = null) { + public function __construct($giturl, $workdir = null, $localdir = null) { + if(session_status() != PHP_SESSION_ACTIVE) { + session_start(); + } + + if(defined("GITMANAGED_EXECUTED")) { + $this->loopedcall = true; + return; + } + if($workdir === null) { $workdir = dirname(__FILE__); - if(!substr($workdir, -1) == "/") + if(substr($workdir, -1) != "/") $workdir .= "/"; $workdir .= ".gitmanaged/"; } - else if(!substr($workdir, -1) == "/") + else if(substr($workdir, -1) != "/") $workdir .= "/"; + if($localdir === null) { + $localdir = dirname(__FILE__); + if(substr($localdir, -1) != "/") + $localdir .= "/"; + } + else if(substr($localdir, -1) != "/") + $localdir .= "/"; + $this->giturl = $giturl; $this->workdir = $workdir; + $this->localdir = $localdir; - //if(!file_exists($this->workdir) || !is_dir($this->workdir)) { + if(!file_exists($this->workdir) || !is_dir($this->workdir)) { if(file_exists($this->workdir) && !is_dir($this->workdir)) { $this->error(self::ERROR_CRITICAL, "local workdir (".htmlspecialchars($this->workdir).") is not a directory."); return; } $this->setupWorkdir(); - //} + } + $this->ready = true; } /* private function gitcmd(...) @@ -66,11 +90,59 @@ class GITManagedWebpage { } else $argstr .= " ".escapeshellarg($arg); } - $gitcmd = 'git '.escapeshellarg('--git-dir='.$this->workdir.'/repository').$argstr; + $gitcmd = 'git '.escapeshellarg('--git-dir='.$this->workdir.'repository/.git').' '.escapeshellarg('--work-tree='.$this->workdir.'repository').$argstr; $output = shell_exec($gitcmd); return $output; } + /* private function setConfig($name, $value) + * store a option in the configuration + */ + private function setConfig($name, $value) { + $this->config[strtolower($name)] = $value; + $this->config_changed = true; + } + + private function checkConfigIntegrity() { + foreach($this->config as $key => $value) { + if(substr($key, 0, strlen('branch_')) == 'branch_') { + if(!file_exists($this->workdir.$key)) { + unset($this->config['key']); + } + } + } + } + + /* private function getConfig($name) + * get an option from the configuration + */ + private function getConfig($name) { + if($this->config == null) { + if(!$this->ready) + return null; + if(file_exists($this->workdir."config.txt")) { + $config_txt = @file_get_contents($this->workdir."config.txt"); + $this->config = unserialize($config_txt); + $this->checkConfigIntegrity(); + } else { + $this->config = array(); + return null; + } + } + if(array_key_exists(strtolower($name), $this->config)) + return $this->config[strtolower($name)]; + else + return null; + } + + private function saveConfig() { + if($this->config_changed && $this->ready) { + $fp = fopen($this->workdir."config.txt", "w"); + fwrite($fp, serialize($this->config)); + fclose($fp); + } + } + /* private function setupWorkdir() * Setup local GITManagedWebpage Work directory with git repository */ @@ -83,24 +155,186 @@ class GITManagedWebpage { } mkdir($this->workdir); - mkdir($this->workdir.'/repository'); - shell_exec('git clone '.escapeshellarg($this->giturl).' '.escapeshellarg($this->workdir.'/repository')); + mkdir($this->workdir.'repository'); + shell_exec('git clone '.escapeshellarg($this->giturl).' '.escapeshellarg($this->workdir.'repository')); $gitok = $this->gitcmd("status"); if(preg_match("#Not a git repository#", $gitok)) { - rmdir($this->workdir.'/repository'); + rmdir($this->workdir.'repository'); rmdir($this->workdir); $this->error(self::ERROR_CRITICAL, "error cloning git repository."); return; } + $this->ready = true; + $default_branch = str_replace(array("\r", "\n"), array("", ""), $this->gitcmd("rev-parse", "--abbrev-ref", "HEAD")); + $this->setConfig("defaultbranch", $default_branch); + $this->saveConfig(); + } + + private function getActiveBranch() { + if($this->activeSession) + return $this->activeSession; + else if(isset($_SESSION[self::SESSION_PREFIX.'branch'])) + return $_SESSION[self::SESSION_PREFIX.'branch']; + else + return $this->getConfig("defaultbranch"); + } + + private function setActiveBranch($branch, $remember) { + $this->activeSession = $branch; + if($remember) + $_SESSION[self::SESSION_PREFIX.'branch'] = $branch; + } + + private function getLocalUntrackedFiles() { + $default_branch = $this->getConfig("defaultbranch"); + $tracked_files = $this->gitcmd("ls-tree", $default_branch, "--full-name", "--name-only"); + $local_files = shell_exec("find ".escapeshellarg($this->localdir)); + $untracked_files = array(); + $tracked_files = explode("\n", str_replace(array("\r"), array(""), $tracked_files)); + $local_files = explode("\n", str_replace(array("\r"), array(""), $local_files)); + + foreach($local_files as $local_file) { + if(!$local_file) + continue; + if($strip_local || (($strip_local = strlen($this->localdir)) && substr($local_file, 0, $strip_local) == $this->localdir)) { + $local_file = substr($local_file, $strip_local); + } + $tracked = false; + foreach($tracked_files as $tracked_file) { + if($tracked_file == $local_file) { + $tracked = true; + break; + } + } + if(!$tracked) { + $untracked_files[] = $local_file; + } + } + return $untracked_files; + } + + private function branchExists($branch) { + //check if branch exists + $gitret = $this->gitcmd("rev-list", "--max-count=1", $branch); + if(!preg_match("#([a-z0-9]{40})#", $gitret, $match)) + return false; + else + return $match[1]; + } + + private function localBranchPath($branch, $create = false) { + $default_branch = $this->getConfig("defaultbranch"); + if($branch == $default_branch) + $dir = $this->localdir; + else + $dir = $this->workdir.'branch_'.str_replace(array('/'), array('_'), $branch).'/'; + if(file_exists($dir)) + return $dir; + else if($create) { + mkdir($dir); + return $dir; + } else + return false; + } + + private function updateBranch($branch, $path, $force = false) { + if(substr($path, -1) != '/') + $path .= '/'; + $current_branch = str_replace(array("\r", "\n"), array("", ""), $this->gitcmd("rev-parse", "--abbrev-ref", "HEAD")); + if($current_branch != $branch) + $this->gitcmd("checkout", $branch); + $this->gitcmd("pull"); + $gitret = $this->gitcmd("rev-list", "--max-count=1", $branch); + preg_match("#([a-z0-9]{40})#", $gitret, $match); + $newest_version = $match[1]; + + $deleted_files = array(); + if(($current_version = $this->getConfig('version_'.$branch))) { + if($current_version == $newest_version && !$force) + return; + else { + $override_all = true; + $delfiles = $this->gitcmd("diff", "--diff-filter=D", "--name-only", $current_version, $newest_version); + $delfiles = explode("\n", str_replace(array("\r"), array(""), $delfiles)); + foreach($delfiles as $file) { + if(!$file) + continue; + $deleted_files[] = $file; + } + } + } else + $override_all = true; + if($override_all) { + $rsync_present = preg_match("#rsync#", `which rsync`); + if($rsync_present) + shell_exec('rsync -avz --exclude ".git" '.escapeshellarg($this->workdir."repository/").' '.escapeshellarg($path)); + else + shell_exec('tar -c --exclude ".git" -C '.escapeshellarg($this->workdir."repository").' . | tar -x -C '.escapeshellarg($path)); + + // remove deleted files + foreach($deleted_files as $file) { + unlink($path.$file); + } + } + $this->setConfig('version_'.$branch, $newest_version); + $this->saveConfig(); } /* public function update() - * Pulls latest commit of active branch and overwrites local files + * Pulls latest commit of active branch and overwrites files in branch folder */ public function update() { + if($this->loopedcall) + return; + + $active_branch = $this->getActiveBranch(); + + if(!$this->branchExists($active_branch)) + return false; + $dir = $this->localBranchPath($active_branch, true); + $this->updateBranch($active_branch, $dir); + } + + public function setBranch($branch, $remember = false) { + if($this->loopedcall) + return; + + if(!$this->branchExists($branch)) { + if(!$this->branchExists('origin/'.$branch)) + return false; + } + $this->setActiveBranch($branch, $remember); + + if(!$this->localBranchPath($branch)) { + $dir = $this->localBranchPath($branch, true); + $this->updateBranch($branch, $dir, true); + } + } + public function getExecFile($file = null) { + if($this->loopedcall) + return; + define("GITMANAGED_EXECUTED", true); + + if(!$file) + $file = $_SERVER['PHP_SELF']; + if($file[0] == '/') + $file = substr($file, 1); + + $default_branch = $this->getConfig("defaultbranch"); + $active_branch = $this->getActiveBranch(); + if($active_branch != $default_branch) { + if(!($dir = $this->localBranchPath($branch))) { + $dir = $this->localBranchPath($active_branch, true); + $this->updateBranch($active_branch, $dir, true); + } + chdir($dir); + return $dir.$file; + } else { + return $file; + } } }