<?php
//
// This is a set of fixes that must be applied when the software is upgraded.
// If the structure of authorized_keys may change, we must add a fix to mark
// the stat dirty.
//
include_once($INC . "/sql.inc.php");
include_once($INC . "/state.inc.php");
include_once($INC . "/util.inc.php");
include_once($INC . "/user.inc.php");
include_once($INC . "/repo.inc.php");
$rg_fixes = array();
$rg_fixes[1] = array("rg_fixes_user_index_by_id");
$rg_fixes[2] = array("rg_fixes_repo_index_by_id");
// This must be the last line
$rg_fixes_ver = count($rg_fixes);
/*
* Fix one repo (make the names as relative links to ids)
*/
function rg_fixes_repo_index_by_id_one($uid, $repo_id, $repo_name)
{
rg_log("Fix repo path: uid=$uid repo_id=$repo_id repo_name=$repo_name");
$ret = FALSE;
do {
// we expect to have a folder .../repos/by_id
$by_id = rg_repo_path_by_id($uid, $repo_id);
$p = dirname($by_id);
if (!is_dir($p) && (mkdir($p, 0755, TRUE) === FALSE)) {
rg_log("Cannot create [$p] folder!");
break;
}
// we expect to have a folder .../repos/by_name
$by_name = rg_repo_path_by_name($uid, $repo_name);
$p = dirname($by_name);
if (!is_dir($p) && (mkdir($p, 0755, TRUE) === FALSE)) {
rg_log("Cannot create [$p] folder!");
break;
}
// We already moved it?
$new_path = rg_repo_path_by_id($uid, $repo_id);
if (!is_dir($new_path)) {
$old_path = rg_user_path_by_id($uid) . "/repos/" . $repo_name . ".git";
$r = rename($old_path, $new_path);
if ($r !== TRUE) {
rg_log("Cannot rename $old_path -> $new_path!");
break;
}
}
// Now, make links from by_name
if (!is_link($by_name)) {
$by_id_rel = rg_repo_path_by_id_rel($uid, $repo_id);
$r = symlink($by_id_rel, $by_name);
if ($r !== TRUE) {
rg_log("Cannot symlink $by_id_rel <- $by_name ($php_errormsg)!");
break;
}
}
$ret = TRUE;
} while (0);
return $ret;
}
/*
* Reindex repos by id so we can rename repos easier.
* And is more normal to index them by the unique id.
*/
function rg_fixes_repo_index_by_id($db)
{
rg_prof_start("fixes_repo_index_by_id");
$ret = FALSE;
do {
$sql = "SELECT uid, repo_id, name FROM repos"
. " WHERE git_dir_done > 0";
$res = rg_sql_query($db, $sql);
if ($res === FALSE)
break;
$all_repos_moved = TRUE;
while (($row = rg_sql_fetch_array($res))) {
$r = rg_fixes_repo_index_by_id_one($row['uid'],
$row['repo_id'], $row['name']);
if ($r !== TRUE) {
$all_repos_moved = FALSE;
break;
}
}
rg_sql_free_result($res);
if ($all_repos_moved !== TRUE)
break;
$ret = TRUE;
} while (0);
rg_prof_end("fixes_repo_index_by_id");
return $ret;
}
/*
* Index user by id and make links for names
*/
function rg_fixes_user_index_by_id_one($uid, $username)
{
global $rg_repos;
rg_log("Fix user path: uid=$uid username=$username");
$ret = FALSE;
do {
$user_path_uid = rg_user_path_by_id($uid);
$user_path_name = rg_user_path_by_name($username);
rg_log("\tuser_path=[$user_path_uid][$user_path_name]");
// parend dir exits? if not, create it
$p = dirname($user_path_uid);
if (!is_dir($p) && (mkdir($p, 0755, TRUE) === FALSE)) {
rg_log("cannot create parent dir [$p]");
break;
}
// parend dir exits? if not, create it
$p = dirname($user_path_name);
if (!is_dir($p) && (mkdir($p, 0755, TRUE) === FALSE)) {
rg_log("cannot create parent dir [$p]");
break;
}
// We already moved it?
if (!is_dir($user_path_uid)) {
$x = $username . "_";
$old_path = $rg_repos . "/users/" . $x[0] . "/" . $x[1]
. "/" . $username;
if (!is_dir($old_path)) {
$ret = TRUE;
break;
}
$r = rename($old_path, $user_path_uid);
if ($r !== TRUE) {
rg_log("Cannot rename $old_path -> $user_path_uid!");
break;
}
}
// Now, make links from name to id
if (!is_link($user_path_name)) {
$by_id_rel = rg_user_path_by_id_rel($uid);
$r = symlink($by_id_rel, $user_path_name);
if ($r !== TRUE) {
rg_log("Cannot symlink $by_id_rel <- $user_path_name ($php_errormsg)!");
break;
}
}
$ret = TRUE;
} while (0);
return $ret;
}
/*
* Reindex users by id so we can rename users easier.
* And is more normal to index them by the unique id.
*/
function rg_fixes_user_index_by_id($db)
{
global $rg_repos;
rg_prof_start("fixes_user_index_by_id");
$ret = FALSE;
do {
$sql = "SELECT uid, username FROM users";
$res = rg_sql_query($db, $sql);
if ($res === FALSE)
break;
$all_users_moved = TRUE;
while (($row = rg_sql_fetch_array($res))) {
$r = rg_fixes_user_index_by_id_one($row['uid'],
$row['username']);
if ($r !== TRUE) {
$all_users_moved = FALSE;
break;
}
}
rg_sql_free_result($res);
if ($all_users_moved !== TRUE)
break;
// Remove old structure dirs
$r = rg_rmdir($rg_repos . "/users");
if ($r === FALSE) {
rg_log("Cannot remove old structure dirs"
. " (" . rg_util_error() . ").");
break;
}
$ret = TRUE;
} while (0);
rg_prof_end("fixes_user_index_by_id");
return $ret;
}
/*
* Apply fixes
*/
function rg_fixes_run($db, $old_ver)
{
global $rg_fixes;
global $rg_fixes_ver;
rg_log("rg_fixes_run: old_ver=$old_ver...");
for ($i = $old_ver + 1; $i <= $rg_fixes_ver; $i++) {
foreach ($rg_fixes[$i] as $function) {
rg_log("Calling function $function...");
$r = $function($db);
if ($r !== TRUE) {
rg_log("Function $function returned error!");
return FALSE;
}
}
}
return TRUE;
}
/*
* Tests if fixes are needed. Return old version
*/
function rg_fixes_needed($db)
{
global $rg_fixes_ver;
rg_log("fixes_needed:");
$old = rg_state_get($db, "fixes_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_fixes_ver");
if ($old == $rg_fixes_ver) {
rg_log("\tDEBUG: fixes are up to date!");
return FALSE;
}
return $old;
}
/*
* Apply fixes 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_fixes_update($db)
{
global $rg_fixes_ver;
rg_log("fixes_update:");
$old = rg_fixes_needed($db);
if ($old === FALSE)
return TRUE;
// If we cannot lock, return error
if (rg_lock("fixes.lock") === FALSE)
return FALSE;
$ret = FALSE;
$rollback = 0;
do {
$r = rg_fixes_run($db, $old);
if ($r !== TRUE) {
rg_internal_error("Cannot apply fixes.");
break;
}
$r = rg_state_set($db, "fixes_version", $rg_fixes_ver);
if ($r !== TRUE) {
rg_log("Cannot set state ver (" . rg_state_error() . ")");
break;
}
$ret = TRUE;
} while (0);
rg_unlock("fixes.lock");
return $ret;
}
?>
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