#!/usr/bin/php
<?php

	function get_deploy_data($all=true)
	{
		global $node;
		$dsql="SELECT
				`deploy`.`id` AS deployid,
				`deploy`.`repo_address` AS repo_address,
				IFNULL(`deploy`.`branch`, 'master') AS branch,
				`deploy`.`login` AS login,
				`deploy`.`password` AS password,
				`deploy`.`hook_pre` AS hook_pre,
				`deploy`.`hook_post` AS hook_post,
				`vhosts`.`writable` AS writable,
				`vhosts`.`id` AS vhostid,
				`vhosts`.`host` AS host,
				`domain`.`name` AS domain,
				`vhosts`.`writable` AS writable,
				`vhosts`.`token` AS vhtoken,
				CONCAT(`vhosts`.`host`,'.',`domain`.`name`) AS vhostname,
				CONCAT(`client`.`name`,'/',`domain`.`name`,'/',`vhosts`.`host`) AS deploydir,
				`client`.`id` AS clientid,
				`client`.`name` AS clientname
			FROM `deploy`
			LEFT JOIN `vhosts` ON `deploy`.`vhostid`=`vhosts`.`id`
			LEFT JOIN `domain` ON `vhosts`.`domainid`=`domain`.`id`
			LEFT JOIN `client` ON `domain`.`clientid`=`client`.`id`
			WHERE (`client`.`node`=".$node." OR `client`.`migrate`=1)
			";

		if (!($all))
		{
			$dsql.=" AND `deploy`.`deploy`=1 ";
		}		

		$dsql.=";";

		return DBquery($dsql);
	}

	function git_clone($repo_address, $branch, $login, $password, $rel_repodir)
	{
		global $ini;

		$repo=git_repo_gen($repo_address, $login, $password);
		$repo_path=DEPLOY_ROOT.'/'.$rel_repodir;
		if (!(check_valid_dir($repo_path)))
		{
			logme("deploy: Invalid repository path ($repo_path)");
			return 99;
		}
		logme("deploy: Cloning repository to $repo_path");
		return exec_as_err("git -c http.sslVerify=false clone --bare --branch '$branch' --single-branch '$repo' '$repo_path'");
	}

#	function git_checkout($branch, $vhostname, $rel_deploydir, $uid, $writable, $hook_pre, $hook_post)
	function git_checkout($dd)
	{
		global $ini;

		$uid=$ini['global']['firstuid']+$dd['clientid'];

		$branch=$dd['branch'];
		$vhostname=$dd['vhostname'];
		$rel_deploydir=$dd['deploydir'];
		$writable=$dd['writable'];

		$hook_pre=$dd['hook_pre'];
		$hook_post=$dd['hook_post'];

		//custom envvars for hook scripts
		$hook_env=array();
		$hook_env['VHOSTID']=$dd['vhostid'];
		$hook_env['TOKEN']=$dd['vhtoken'];

		// repo_path is at DEPLOY_ROOT/vhostname
		$repo_path=DEPLOY_ROOT.'/'.$vhostname;

		if (!(check_valid_dir($repo_path)) || !(is_dir($repo_path)))
		{
			logme("deploy: Invalid repository path ($repo_path)");
			return 99;
		}

		$deploy_path=$ini['global']['webroot'].'/'.$rel_deploydir;

		if (!(check_valid_dir($deploy_path)) || !(is_dir($deploy_path)))
		{
			logme("deploy: Invalid deploy path ($deploy_path)");
			return 98;
		}

		logme("deploy: Fetching repository to $repo_path");
		if (exec_as_err("git -c http.sslVerify=false --git-dir='$repo_path' --work-tree='$deploy_path' fetch --prune origin '$branch'") == 0)
		{
			writeall($deploy_path);

			// pre-pre-deploy hook (script)
			exec_hook('pre-pre-deploy', $dd['clientid'], $dd['clientname'], $dd['domain'], $dd['host'], $hook_env, 'www-data');
			// pre-deploy hook (url)
			run_hook('pre-deploy', $vhostname, $hook_pre);
			// pre-deploy hook (script)
			exec_hook('pre-deploy', $dd['clientid'], $dd['clientname'], $dd['domain'], $dd['host'], $hook_env, 'www-data');

			if (exec_as_err("git -c core.fileMode=false --git-dir='$repo_path' --work-tree='$deploy_path' status >/dev/null") == 0)
			{
				logme("deploy: Checkout repository to $deploy_path");
				if (exec_as_err("git -c core.fileMode=false --git-dir='$repo_path' --work-tree='$deploy_path' checkout -f '$branch'") == 0)
				{
					if (exec_as_err("git -c core.fileMode=false --git-dir='$repo_path' --work-tree='$deploy_path' reset --hard FETCH_HEAD") == 0)
					{
						// make everything writable, discard repo privileges
						writeall($deploy_path);

						// post-deploy hook (script)
						exec_hook('post-deploy', $dd['clientid'], $dd['clientname'], $dd['domain'], $dd['host'], $hook_env, 'www-data');
						// post-deploy hook (url)
						run_hook('post-deploy', $vhostname, $hook_post);
						// post-post-deploy hook (script)
						exec_hook('post-post-deploy', $dd['clientid'], $dd['clientname'], $dd['domain'], $dd['host'], $hook_env, 'www-data');

						fixrights($deploy_path, $uid, $writable);
						return 0;
					}
					else
					{
						fixrights($deploy_path, $uid, $writable);
						logme("deploy: GIT reset failed on $deploy_path");
						return 37;
					}
				}
				else
				{
					fixrights($deploy_path, $uid, $writable);
					logme("deploy: GIT checkout failed to $deploy_path");
					return 34;
				}
			}
			else
			{
				fixrights($deploy_path, $uid, $writable);
				logme("deploy: GIT status failed on $deploy_path");
				return 39;
			}
		}
		else
		{
			logme("deploy: GIT fetch failed to $repo_path");
			return 35;
		}
	}

	function git_repo_gen($repo_address, $login, $password)
	{
		$protocol=preg_replace('#\:\/\/.*$#','',$repo_address);
		$address=preg_replace('#^.*\/\/#','',$repo_address);
		return $protocol.'://'.urlencode($login).':'.urlencode($password).'@'.$address;
	}


	function check_deploy_cache()
	{
		global $ini;
		global $node;

		$dres=get_deploy_data(1);

		$deploy_arr=array();
		while ($drow=$dres->fetch_assoc()) {
			$deploy_arr[]=$drow['vhostname'];
		}

		//get cached repository list
		$deploy_cache_arr=listdir(DEPLOY_ROOT);

		$todel=array_diff($deploy_cache_arr,$deploy_arr);
		$toclone=array_diff($deploy_arr, $deploy_cache_arr);

		foreach($todel as $dirdel)
		{
			$fqd=DEPLOY_ROOT.'/'.$dirdel;
			if (check_valid_dir($fqd) && is_dir($fqd))
			{
				logme('deploy: cache deleted: '.$fqd);
				exec_as_err('rm -rf '.$fqd);
			}
		}

		$dres->data_seek(0);
		while ($drow=$dres->fetch_assoc())
		{
			$deploy_uid=$ini['global']['firstuid']+$drow['clientid'];
			$deployid=$drow['deployid'];

			if (in_array($drow['vhostname'], $toclone))
			{
				if (git_clone($drow['repo_address'], $drow['branch'], $drow['login'], $drow['password'], $drow['vhostname']) != 0)
				{
					DBquery("UPDATE `deploy` SET `deploy`='3' WHERE `id` = '$deployid';");
				}
			}
		}

	}

	function deploy_all()
	{
		global $ini;
		global $node;

		$dres=get_deploy_data(0);

		while ($drow=$dres->fetch_assoc())
		{
			//$deploy_uid=$ini['global']['firstuid']+$drow['clientid'];
			$deployid=$drow['deployid'];

#			if(git_checkout($drow['branch'], $drow['vhostname'], $drow['deploydir'], $deploy_uid, $drow['writable'], $drow['hook_pre'], $drow['hook_post']) == 0)
			if(git_checkout($drow) == 0)
			{
				DBquery("UPDATE `deploy` SET `deploy`='0', `last`=NOW() WHERE `id` = '$deployid';");
			}
			else
			{
				DBquery("UPDATE `deploy` SET `deploy`='2' WHERE `id` = '$deployid';");
			}
		}
	}

	function run_hook($type, $vhostname, $hook=NULL)
	{
		if ($hook)
		{
			logme("deploy: running ".$type." hook '$vhostname/$hook'");

			if (function_exists('curl_version'))
			{
				// use PHP curl if installed
				$hc = curl_init();

				curl_setopt($hc, CURLOPT_AUTOREFERER, FALSE);		// don't set Referer when redirected
				curl_setopt($hc, CURLOPT_HEADER, 1);			// include headers in output
				curl_setopt($hc, CURLOPT_RETURNTRANSFER, 1);		// put output in string (instrad of just displaying)
				curl_setopt($hc, CURLOPT_FOLLOWLOCATION, TRUE);		// follow redirects

				curl_setopt($hc, CURLOPT_SSL_VERIFYPEER, FALSE);	// no check peer cert
				curl_setopt($hc, CURLOPT_SSL_VERIFYHOST, 0);		// no check cert names

				curl_setopt($hc, CURLOPT_URL, 'http://'.$vhostname.'/'.$hook);
				$hook_out = curl_exec($hc);
				curl_close($hc);
			}
			else
			{
				//fall back to PHP internal function
				$hook_out=file_get_contents('http://'.$vhostname.'/'.$hook);
			}

			if ($hook_out === false) {
				logme("deploy: ".$type." hook FAILED '$vhostname/$hook'");
			}

		}
	}


###########################################################################

/// init

	global $ini;
	global $node;

	require(dirname(__FILE__)."/../include/functions.php");
	check_force_run(1);
	init();

	if (get_ini_opt('confgen','deploy') === '0') { exit(0); }

	define('DEPLOY_ROOT',$ini['global']['webroot'].'/sys/git');
	checkdir(DEPLOY_ROOT,33,33);

	//check if there is anything to update (exit if none)
	check_update('deploy');

	//check repositories - clone/delete
	check_deploy_cache();

	//deploy if needed
	deploy_all();

	//finish
	unlock_update('deploy');
