xaizek / rocketgit (License: AGPLv3+) (since 2018-12-09)
Light and fast Git hosting solution suitable to serve both as a hub or as a personal code storage with its tickets, pull requests, API and much more.
<root> / inc / struct.inc.php (60e8bfbb71ff1c4bbf71a65c4b7cabaa8bc09940) (8,543B) (mode 100644) [raw]
<?php
include_once($INC . "/sql.inc.php");
include_once($INC . "/state.inc.php");
include_once($INC . "/util.inc.php");

define("RG_DROP_TABLES", 1);
define("RG_IGNORE_ERRORS", 1 << 1);

$rg_sql_struct = array();
$rg_sql_struct[1] = array();
$rg_sql_struct[1]['tables'] = array(
	"repos" => "CREATE TABLE repos"
		. " (repo_id SERIAL PRIMARY KEY"
		. ", name TEXT UNIQUE NOT NULL"
		. ", uid INTEGER NOT NULL"
		. ", itime INTEGER NOT NULL"
		. ", disk_quota_mb INTEGER DEFAULT 0"
		. ", disk_used_mb INTEGER NOT NULL DEFAULT 0"
		. ", max_commit_size INTEGER DEFAULT 0"
		. ", master INTEGER NOT NULL DEFAULT 0"
		. ", description TEXT NOT NULL DEFAULT ''"
		. ", git_dir_done INTEGER NOT NULL DEFAULT 0"
		. ", default_rights TEXT NOT NULL DEFAULT ''"
		. ", deleted INTEGER NOT NULL DEFAULT 0"
		. ", max_users INTEGER NOT NULL DEFAULT 0"
		. ")",
	"rights" => "CREATE TABLE rights"
		. " (type TEXT NOT NULL"
		. ", obj_id INTEGER NOT NULL"
		. ", uid INTEGER NOT NULL"
		. ", rights TEXT NOT NULL"
		. ", itime INTEGER NOT NULL)",
	"state" => "CREATE TABLE state"
		. " (var TEXT PRIMARY KEY"
		. ", value TEXT NOT NULL)",
	"keys" => "CREATE TABLE keys"
		. " (key_id SERIAL PRIMARY KEY"
		. ", itime INTEGER NOT NULL"
		. ", uid INTEGER NOT NULL"
		. ", key TEXT UNIQUE NOT NULL)",
	"users" => "CREATE TABLE users"
		. " (uid SERIAL PRIMARY KEY"
		. ", username TEXT UNIQUE NOT NULL"
		. ", realname TEXT NOT NULL"
		. ", salt TEXT NOT NULL"
		. ", pass TEXT NOT NULL"
		. ", email TEXT NOT NULL"
		. ", itime INTEGER NOT NULL"
		. ", suspended INTEGER NOT NULL DEFAULT 0"
		. ", session_time INTEGER NOT NULL DEFAULT 3600"
		. ", last_seen INTEGER NOT NULL DEFAULT 0"
		. ", is_admin INTEGER NOT NULL DEFAULT 0"
		. ", disk_quota_mb INTEGER NOT NULL DEFAULT 0"
		. ", disk_used_mb INTEGER NOT NULL DEFAULT 0"
		. ", rights TEXT NOT NULL"
		. ", confirmed INTEGER NOT NULL DEFAULT 0"
		. ", confirm_token TEXT NOT NULL DEFAULT ''"
		. ")",
	"sess" => "CREATE TABLE sess"
		. " (sid TEXT PRIMARY KEY"
		. ", uid INTEGER NOT NULL"
		. ", expire INTEGER NOT NULL"
		. ", session_time INTEGER NOT NULL"
		. ", ip TEXT NOT NULL)",
	"forgot_pass" => "CREATE TABLE forgot_pass"
		. " (token TEXT PRIMARY KEY"
		. ", uid INTEGER NOT NULL"
		. ", expire INTEGER NOT NULL)",
	"tokens" => "CREATE TABLE tokens"
		. " (token TEXT PRIMARY KEY"
		. ", sid TEXT NOT NULL"
		. ", expire INTEGER NOT NULL)"
);
$rg_sql_struct[1]['other'] = array();

$rg_sql_struct[2] = array();
$rg_sql_struct[2]['tables'] = array(
	"suggestions" => "CREATE TABLE suggestions"
		. " (suggestion_id SERIAL PRIMARY KEY"
		. ", uid INTEGER NOT NULL"
		. ", email TEXT NOT NULL"
		. ", suggestion TEXT NOT NULL)"
);
$rg_sql_struct[2]['other'] = array();

$rg_sql_struct[3] = array();
$rg_sql_struct[3]['tables'] = array();
$rg_sql_struct[3]['other'] = array(
	"add organization field to user" => "ALTER TABLE users"
		. " ADD organization SMALLINT NOT NULL DEFAULT 0"
);

$rg_sql_struct[4] = array();
$rg_sql_struct[4]['tables'] = array(
	"merge_requests" => "CREATE TABLE merge_requests ("
		. "repo_id INT NOT NULL"
		. ", itime INT NOT NULL"
		. ", namespace TEXT NOT NULL"
		. ", refname TEXT NOT NULL"
		. ", old_rev CHAR(40) NOT NULL"
		. ", new_rev CHAR(40) NOT NULL"
		. ", done INT NOT NULL DEFAULT 0"
		. ", ip TEXT NOT NULL"
		. ")"
);
$rg_sql_struct[4]['other'] = array(
	"merge_request_index_repo_id" => "CREATE INDEX merge_requests_i_repo_id"
		. " ON merge_requests (repo_id)"
);

$rg_sql_struct[5] = array();
$rg_sql_struct[5]['tables'] = array(
	"history_push" => "CREATE TABLE history_push ("
		. "itime INT NOT NULL"
		. ", repo_id INT NOT NULL"
		. ", ip TEXT NOT NULL"
		. ", refname TEXT NOT NULL"
		. ", old_rev CHAR(40) NOT NULL"
		. ", new_rev CHAR(40) NOT NULL"
		. ")"
);

$rg_sql_struct[6] = array();
$rg_sql_struct[6]['tables'] = array(
	"bugs_max" => "CREATE TABLE bugs_max ("
		. "repo_id INT NOT NULL PRIMARY KEY"
		. ", last_bug_id INT NOT NULL"
		. ")",
	"bugs" => "CREATE TABLE bugs ("
		. "repo_id INT NOT NULL"
		. ", bug_id INT NOT NULL"
		. ", itime INT NOT NULL"
		. ", utime INT NOT NULL"
		. ", uid INT NOT NULL"
		. ", ip TEXT NOT NULL"
		. ", title TEXT NOT NULL"
		. ", body TEXT NOT NULL"
		. ", state SMALLINT NOT NULL"
		. ", assigned_uid INT NOT NULL"
		. ", deleted INT NOT NULL"
		. ")",
	"bug_notes" => "CREATE TABLE bug_notes ("
		. "repo_id INT NOT NULL"
		. ", bug_id INT NOT NULL"
		. ", note TEXT NOT NULL"
		. ", itime INT NOT NULL"
		. ", uid INT NOT NULL"
		. ", ip TEXT NOT NULL"
		. ")",
	"bug_labels" => "CREATE TABLE bug_labels ("
		. "repo_id INT NOT NULL"
		. ", bug_id INT NOT NULL"
		. ", label TEXT NOT NULL"
		. ")"
);
$rg_sql_struct[6]['other'] = array(
	"bugs_index_repo_id_bug_id" => "CREATE UNIQUE INDEX bugs_i_repo_id_bug_id"
		. " ON bugs (repo_id, bug_id)",
	"bugs_index_itime" => "CREATE INDEX bugs_i_itime"
		. " ON bugs (itime)",
	"bug_notes_index_repo_id_bug_id" => "CREATE INDEX bug_notes_i_repo_id_bug_id"
		. " ON bug_notes (repo_id, bug_id)",
	"bug_labels_index_repo_id_bug_id" => "CREATE INDEX bug_labels_i_repo_id_bug_id"
		. " ON bug_labels (repo_id, bug_id)"
);

$rg_sql_struct[7] = array();
$rg_sql_struct[7]['tables'] = array(
	"bug_search" => "CREATE TABLE bug_search ("
		. "repo_id INT NOT NULL"
		. ", uid INT NOT NULL"
		. ", name TEXT NOT NULL"
		. ", data TEXT NOT NULL"
		. ", for_all_users SMALLINT NOT NULL"
		. ")"
);
$rg_sql_struct[7]['other'] = array(
	"bug_search_repo_id_uid" => "CREATE INDEX bug_search_i_repo_id_uid"
		. " ON bug_search(repo_id, uid)"
);

// This must be the last line
$rg_sql_schema_ver = count($rg_sql_struct);



/*
 * Generate structure
 */
function rg_sql_struct_run($db, $flags, $old_schema_ver)
{
	global $rg_sql_struct;
	global $rg_sql_schema_ver;

	$ignore_errors = ($flags & RG_IGNORE_ERRORS) ? TRUE : FALSE;
	$drop_tables = ($flags & RG_DROP_TABLES) ? TRUE : FALSE;

	rg_log("sql_struct_run: flags=$flags"
		. " ignore_errors=" . ($ignore_errors ? "Yes" : "No")
		. " drop_tables=" . ($drop_tables ? "Yes" : "No")
		. " old_schema_ver=$old_schema_ver...");

	for ($i = $old_schema_ver + 1; $i <= $rg_sql_schema_ver; $i++) {
		foreach ($rg_sql_struct[$i] as $type => $sqls) {
			if (count($sqls) == 0)
				continue;

			foreach ($sqls as $id => $sql) {
				rg_log("Applying schema $i, type $type, id $id...");

				if ((strcmp($type, "tables") == 0)
					&& ($drop_tables === TRUE)) {
					rg_log("Dropping table [$id]...");
					$sql2 = "DROP TABLE IF EXISTS $id";
					$res = rg_sql_query($db, $sql2);
					if ($res === FALSE) {
						rg_log("WARN: Cannot run sql ($sql2) (" . rg_sql_error() . ")!");
						if (!$ignore_errors)
							return FALSE;
					}
					rg_sql_free_result($res);
				}

				rg_log("Running [$sql]...");
				$res = rg_sql_query($db, $sql);
				if ($res === FALSE) {
					rg_log("WARN: Cannot run sql ($sql) (" . rg_sql_error() . ")!");
					if (!$ignore_errors)
						return FALSE;
				}

				rg_sql_free_result($res);
			}
		}
	}

	return TRUE;
}

/*
 * Tests if schema update is needed. Return old version
 */
function rg_sql_struct_update_needed($db)
{
	global $rg_sql_schema_ver;

	rg_log("sql_struct_update_needed:");

	$old = rg_state_get($db, "schema_version");
	if ($old === FALSE) {
		//TODO: error rg_log("\tDEBUG: schema is up to date!");
		return FALSE;
	}

	if (empty($old))
		$old = 0;

	rg_log("\tDEBUG: old=$old new=$rg_sql_schema_ver");
	if ($old == $rg_sql_schema_ver) {
		rg_log("\tDEBUG: schema is up to date!");
		return FALSE;
	}

	return $old;
}

/*
 * Update schema if needed
 * Returns FALSE in case of error
 * This must not be run by web user because of the owner of the locking file.
 */
function rg_sql_struct_update($db, $flags)
{
	global $rg_sql_schema_ver;

	rg_log("sql_struct_update: flags=$flags");

	$old = rg_sql_struct_update_needed($db);
	if ($old === FALSE)
		return TRUE;

	// If we cannot lock, return error
	if (rg_lock("schema_upgrade.lock") === FALSE)
		return FALSE;

	$ret = FALSE;
	$rollback = 0;
	do {
		if (rg_sql_begin($db) !== TRUE)
			break;

		$rollback = 1;

		$r = rg_sql_struct_run($db, $flags, $old);
		if ($r !== TRUE) {
			rg_log("Cannot update schema (" . rg_sql_error() . ")");
			break;
		}

		$r = rg_state_set($db, "schema_version", $rg_sql_schema_ver);
		if ($r !== TRUE) {
			rg_log("Cannot update schema ver (" . rg_state_error() . ")");
			break;
		}

		if (rg_sql_commit($db) !== TRUE)
			break;

		$rollback = 0;
		$ret = TRUE;
	} while (0);

	if ($rollback == 1)
		rg_sql_rollback($db);

	rg_unlock("schema_upgrade.lock");

	return $ret;
}
?>
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/rocketgit

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/rocketgit

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master