From e78df72edd492c96538aaa5df25f73895ce8c02e Mon Sep 17 00:00:00 2001 From: Matt Housh Date: Sat, 2 Mar 2024 14:33:49 -0600 Subject: [PATCH] timeline: updated to latest live versions after crux.nu server rebuild * rss generator: minor updates for XML output formatting and PHP log warnings * cacher: replaced flyspray task caching with gitea issues caching --- timeline/rss.php | 94 +++---- timeline/timeline.php | 2 +- timeline/tlcacher.php | 626 ++++++++++++++++++++++++------------------ 3 files changed, 410 insertions(+), 312 deletions(-) diff --git a/timeline/rss.php b/timeline/rss.php index 0de711a..e38422c 100644 --- a/timeline/rss.php +++ b/timeline/rss.php @@ -1,59 +1,55 @@ query($sql); -if (!$res) die ("Query error: $last_cached_sql"); + $dbc = new SQLite3($dbfile); -header ("Content-type: text/xml"); -$timeline = ''."\n"; -$timeline .= 'CRUX timelineCRUX: timeline (commits, tasks, wiki edits)http://crux.nu'; + $sql = "SELECT DISTINCT * FROM events ORDER BY event_tstamp DESC LIMIT $limit"; + $res = $dbc->query($sql); + if (!$res) die ("Query error: $last_cached_sql"); -while ($evt =& $res->fetchArray()) { - #print_r($evt); # uncomment for debug + header ("Content-type: text/xml"); + $timeline = "\n\n\n\n"; + $timeline .= " CRUX timeline\n CRUX: timeline (commits, issues, wiki edits)\n http://crux.nu\n"; - $url = $evt['event_url']; - $url = str_replace("&","&", $url); - # strip diff link - $description = preg_replace('/\(\[\[.*\]\]\)/s','', $evt['event_description']); - # strip wiki link with url - $description = preg_replace('/\[\[(.*)\|(\d+)\]\]/s','$2', $description); - # strip users (git) - $description = preg_replace('/\[\[~(.*)\|(.*)\]\]/s','$2', $description); - # strip wiki link without url - $description = preg_replace('/\[\[(\w+)\.(\w+)\]\] /s','$1.$2', $description); - # strip wiki user with ~ - $description = preg_replace('/\[\[~(\w+)\]\] /s','$1', $description); - # Compact description for git commits - $description = preg_replace('/\[\[http(.*)\|(.*)\]\] committed by/','$2 by', $description); - # Compact description for wiki edits - $description = str_replace ("Wiki page ","", $description); + while ($evt = $res->fetchArray()) { + #print_r($evt); # uncomment for debug - $notes = ""; - $titlenotes = ""; - if ($evt['event_notes'] != "") { - $notes = $evt['event_notes']; - $titlenotes = ": ".$notes; - if (strlen($notes) > 40) { - $titlenotes = ": ".substr($notes,0,40)."..."; - } - } - $timeline .= " - - $description$titlenotes - $notes - $url - \n"; -} -$timeline .= "\n"; -echo $timeline; + $url = $evt['event_url']; + $url = str_replace("&","&", $url); + # strip diff link + $description = preg_replace('/\(\[\[.*\]\]\)/s','', $evt['event_description']); + # strip wiki link with url + $description = preg_replace('/\[\[(.*)\|(\d+)\]\]/s','$2', $description); + # strip users (git) + $description = preg_replace('/\[\[~(.*)\|(.*)\]\]/s','$2', $description); + # strip wiki link without url + $description = preg_replace('/\[\[(\w+)\.(\w+)\]\] /s','$1.$2', $description); + # strip wiki user with ~ + $description = preg_replace('/\[\[~(\w+)\]\] /s','$1', $description); + # Compact description for git commits + $description = preg_replace('/\[\[http(.*)\|(.*)\]\] committed by/','$2 by', $description); + # Compact description for wiki edits + $description = str_replace ("Wiki page ","", $description); + + $notes = ""; + $titlenotes = ""; + if ($evt['event_notes'] != "") { + $notes = $evt['event_notes']; + $titlenotes = ": ".$notes; + if (strlen($notes) > 40) { + $titlenotes = ": ".substr($notes,0,40)."..."; + } + } + $timeline .= " \n $description$titlenotes\n $notes\n $url\n \n"; + } + $timeline .= "\n\n"; + echo $timeline; ?> diff --git a/timeline/timeline.php b/timeline/timeline.php index 6ef3fc0..5053cc7 100755 --- a/timeline/timeline.php +++ b/timeline/timeline.php @@ -99,7 +99,7 @@ function GetEvents() { } $timeline .= "\n"; - $timeline .= '
Show the latest days
'."\n"; + $timeline .= '
Show the latest days
'."\n"; return $timeline; } diff --git a/timeline/tlcacher.php b/timeline/tlcacher.php index e77dcdc..0b99227 100755 --- a/timeline/tlcacher.php +++ b/timeline/tlcacher.php @@ -1,283 +1,385 @@ #!/usr/bin/php "PerLiden", - "Matt Housh" => "MattHoush", - "Juergen Daubert" => "JuergenDaubert", - "Johannes Winkelmann" => "JohannesWinkelmann", - "Simone Rota" => "SimoneRota" , - "Jason Thomas Dolan" => "JasonThomasDolan", - "Jukka Heino" => "JukkaHeino", - "Tilman Sauerbeck" => "TilmanSauerbeck", - "Simon Gloßner" => "SimonGloßner", - "Nick Steeves" => "NickSteeves", - "Antti Nykänen" => "AnttiNykänen", - "Antti Nykanen" => "AnttiNykänen", - "Jose V Beneyto" => "JoseVBeneyto", - "JoseVBeneyto" => "JoseVBeneyto", - "Lucas Hazel" => "LucasHazel", - "Thomas Penteker" => "ThomasPenteker", - "Fredrik Rinnestam" => "FredrikRinnestam", - "Danny Rawlins" => "DannyRawlins", - "Tim Biermann" => "TimBiermann", -); - -// Path of the recent changes pmwiki file -$wiki_file = '/var/www/htdocs/wiki.d/Site.AllRecentChanges'; - -// Event: cache_id, tstamp, type(icon), date, time, user, url, description, notes -$events = array(); - -/**************** Last cached events *******************/ + /* + Caches timeline events from git, gitea issues, and pmwiki + into a SQLite3 database. + */ -$dbc = new SQLite3($dbfilec); + /* configuration */ + require_once('tlcacher_config.php'); -print("Fetching last cached flyspray event."); -$last_cached_sql = "select cache_id from events where event_type like 'task%' order by cache_id desc limit 1"; -$res = $dbc->query($last_cached_sql); -if (!$res) die ("Query error: $last_cached_sql"); -$row = $res->fetchArray(SQLITE3_ASSOC); -if (!$row) { - $last_task = 0; -} else { - $last_task = $row['cache_id']; -} -print(" [$last_task]\n"); + // server timezone + $tz = new DateTimeZone("Europe/Stockholm"); -print("Fetching last cached wiki event."); -$last_cached_sql = "select cache_id from events where event_type = 'wiki_changed' order by cache_id desc limit 1"; -$res = $dbc->query($last_cached_sql); -if (!$res) die ("Query error: $last_cached_sql"); -$row = $res->fetchArray(SQLITE3_ASSOC); -if (!$row) { - $last_wiki = 0; -} else { - $last_wiki = $row['cache_id']; -} -print(" [$last_wiki]\n"); + // gitea base URL + $base_url = "https://git.crux.nu"; -function last_cached_git($repo) { - global $dbc; - $last_cached_sql = "select cache_id from events where event_type='git_commit_$repo' order by event_tstamp desc limit 1"; - $res = $dbc->query($last_cached_sql); - if (!$res) die ("Query error: $last_cached_sql"); - $row = $res->fetchArray(SQLITE3_ASSOC); - if (!$row) { - $last_git = ""; - } else { - $last_git = $row['cache_id']; - } - return $last_git; -} + // gitea commit base URL + $git_url = "{$base_url}/%s/commit/%s"; -/**************** Flyspray events ***********************/ -print("\nProcessing flyspray events.\n"); + // git repos for which to cache events + // append ":branch" to the repo name to restrict logs to 'branch' + $git_repos = array("ports/core:3.7", "ports/opt:3.7", "ports/xorg:3.7", "ports/compat-32:3.7", "tools/pkgutils", "system/iso"); -$sql = 'select history_id, event_date, event_type, user_name, flyspray_history.task_id, item_summary, closure_comment, real_name - from flyspray_history - join flyspray_users on flyspray_users.user_id = flyspray_history.user_id - join flyspray_tasks on flyspray_tasks.task_id = flyspray_history.task_id - where history_id > ?'; + // path to git repositories on disk + $git_root = "/home/gitea/git"; -$stmt = $pdo->prepare($sql); -$stmt->execute([$last_task]); + // Map git authors to wiki profiles + $git_username_map = array( + "Per Lidén" => "PerLiden", + "Matt Housh" => "MattHoush", + "Juergen Daubert" => "JuergenDaubert", + "Johannes Winkelmann" => "JohannesWinkelmann", + "Simone Rota" => "SimoneRota" , + "Jason Thomas Dolan" => "JasonThomasDolan", + "Jukka Heino" => "JukkaHeino", + "Tilman Sauerbeck" => "TilmanSauerbeck", + "Simon Gloßner" => "SimonGloßner", + "Nick Steeves" => "NickSteeves", + "Antti Nykänen" => "AnttiNykänen", + "Antti Nykanen" => "AnttiNykänen", + "Jose V Beneyto" => "JoseVBeneyto", + "JoseVBeneyto" => "JoseVBeneyto", + "Lucas Hazel" => "LucasHazel", + "Thomas Penteker" => "ThomasPenteker", + "Fredrik Rinnestam" => "FredrikRinnestam", + "Danny Rawlins" => "DannyRawlins", + "Tim Biermann" => "TimBiermann", + ); -while ($row =& $stmt->fetch()) { - $etype = $row['event_type']; - $euser = $row['real_name']; - $etid = $row['task_id']; - $edate = $row['event_date']; - $cache_id = $row['history_id']; - $description = ""; - $date = date("Y-m-d", $edate); - $time = date("H:i", $edate); - $url = sprintf($task_url,$etid); - switch ($etype) { - case "1": // new task - $icon = "task_opened"; - $description = "New task [[$url|$etid]] opened by $euser"; - $notes = $row['item_summary']; - break; - case "2": // task closed - $icon = "task_closed"; - $description = "Task [[$url|$etid]] closed by $euser"; - if ($row['closure_comment'] != "" && $row['closure_comment'] != 0) { // weird flyspray! - $notes = $row['closure_comment']; - } else { - $notes = ""; - } - break; - case "3": // task edited : fields, comments, attachments, ownership, related tasks, etc. - case "4": - case "5": - case "6": - case "7": - case "8": - case "14": - case "15": - case "16": - case "22": - case "23": - case "24": - case "25": - $icon = "task_changed"; - $description = "Task [[$url|$etid]] modified by $euser"; - $notes = ""; - break; - } - if ($description !== "") { - $events[] = array( 'cache_id' => $cache_id, 'tstamp' => $edate, 'icon' => $icon, 'date' => $date, - 'time' => $time, 'user' => $euser, 'url'=> $url, 'description' => $description, 'notes' => $notes,); - } -} + // Path of the recent changes pmwiki file + $wiki_file = '/var/www/pmwiki/wiki.d/Site.AllRecentChanges'; -/****************** PmWiki events *********************/ + // Event: cache_id, tstamp, type(icon), date, time, user, url, description, notes + $events = array(); -print("\nProcessing wiki events.\n"); + /**************** Last cached events *******************/ -$lines = file($wiki_file); -$chline = ""; -foreach ($lines as $line) { - $line = urldecode($line); - if (substr($line,0,5) == "text=") { - $chline = substr($line,7); - } -} + $dbc = new SQLite3($dbfilec); -if ($chline != "") { - $wikiedits = explode("*", $chline); - $icon = "wiki_changed"; - foreach ($wikiedits as $ed) { - preg_match('/\[\[.*\]\] ./', $ed, $matches); - $page = $matches[0]; - preg_match('/by \[\[.*\]\]/', $ed, $matches); - if (sizeof($matches) != 0) { - $user = $matches[0]; - } else { - $user = "unknown"; - } - preg_match("/\=(.*)\=/s",$ed,$matches); - $notes = $matches[1]; - preg_match("/\. \. \. (.*?) by/s",$ed,$matches); - $date = $matches[1]; - $date = str_replace(", at", "", $date); // old entry format - $tstamp = strtotime($date); - preg_match('/(..\:..)/',$date,$matches); - $time = $matches[0]; - $date = date("Y-m-d", $tstamp); - $action = "?action=diff#" . urlencode($date . " " . $time) . "|diff"; - $page_diff = trim(str_replace("]]", $action."]]", $page)); - preg_match('/\[\[(.*)\|diff\]\]/', $page_diff, $matches); - $url = $matches[1]; - $url = "https://crux.nu/".str_replace(".","/", $url); - $description = "Wiki page $page edited $user ($page_diff)"; - if ($tstamp > $last_wiki) { - $events[] = array( 'cache_id' => $tstamp, 'tstamp' => $tstamp, 'icon' => $icon, 'date' => $date, - 'time' => $time, 'user' => $user, 'url' => $url, 'description' => $description, 'notes' => $notes); - } - //print_r($events); - } -} - -/******************* Git events ***********************/ - -print("\nProcessing git events.\n"); - -foreach ($git_repos as $repo) { - $branch = ""; - if (strpos($repo, ":") !== FALSE) { - $tmp = explode(':', $repo); - $repo = $tmp[0]; - $branch = $tmp[1]; - } - $pos = strpos($repo, "/"); - $reponame = substr($repo, $pos+1); - $last_git = last_cached_git($reponame); - print("Last cached commit for $repo: $last_git\n"); - $out = array(); - $res = 0; - $done = array(); - exec("GIT_DIR=$git_root/$repo.git git log -n 1 $branch", $out, $res); - $git_latest = trim(str_replace("commit ", "", $out[0])); - unset($out); - $res = 0; - if ($git_latest != $last_git) { - if ($last_git == "") { - exec("GIT_DIR=$git_root/$repo.git git log $branch", $out, $res); - } else { - exec("GIT_DIR=$git_root/$repo.git git log $last_git..$git_latest $branch", $out, $res); - } - $last_git = $git_latest; - foreach ($out as $line) { - if (substr($line, 0, 7) == "commit ") { - $rev = substr($line, 7); - $url = sprintf($git_url, $repo, $rev); - $compact_rev = substr($rev,0,4)."..".substr($rev,-4,4); - $revurl = "[[$url|$compact_rev]]"; - } else if (substr($line, 0, 7) == "Merge: ") { - } else if (substr($line, 0, 8) == "Author: ") { - $user = substr($line, 8); - $pos = strpos($user, "<"); - if ($pos !== FALSE) - $user = trim(substr($user,0,$pos)); - if (array_key_exists($user, $git_username_map)) { - $wikiname = $git_username_map[$user]; - $user = "[[~" . $wikiname . "|" . $user . "]]"; - } - $description = "$revurl committed by $user"; - } else if (substr($line, 0, 8) == "Date: ") { - $date = substr($line, 8); - $tstamp = strtotime($date); - $date = date("Y-m-d", $tstamp); - $time = date("H:i", $tstamp); - } else if (trim($line) != "" && !array_key_exists($rev, $done)) { - $icon = "git_commit_$reponame"; - $notes = trim($line); - $events[] = array( 'cache_id' => $rev, 'tstamp' => $tstamp, 'icon' => $icon, 'date' => $date, - 'time' => $time, 'user' => $user, 'url'=>$url, 'description' => $description, 'notes' => $notes); - $done[$rev] = 1; - } - } + print("Fetching last cached gitea issues event."); + $last_cached_sql = "SELECT cache_id FROM events WHERE event_type LIKE 'task%' ORDER BY cache_id DESC LIMIT 1"; + $res = $dbc->query($last_cached_sql); + if (!$res) die ("Query error: $last_cached_sql"); + $row = $res->fetchArray(SQLITE3_ASSOC); + if (!$row) { + $last_task = 0; + } else { + $last_task = $row['cache_id']; } -} + print(" [$last_task]\n"); -/*************** Finally, all events *********************/ -$sql = 'INSERT INTO events VALUES (NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; -foreach ($events as $evt) { - $stmt = $dbc->prepare($sql); - $stmt->bindValue(1, $evt['cache_id'], SQLITE3_TEXT); - $stmt->bindValue(2, $evt['tstamp'], SQLITE3_INTEGER); - $stmt->bindValue(3, $evt['icon'], SQLITE3_TEXT); - $stmt->bindValue(4, $evt['date'], SQLITE3_TEXT); - $stmt->bindValue(5, $evt['time'], SQLITE3_TEXT); - $stmt->bindValue(6, $evt['user'], SQLITE3_TEXT); - $stmt->bindValue(7, $evt['url'], SQLITE3_TEXT); - $stmt->bindValue(8, $evt['description'], SQLITE3_TEXT); - $stmt->bindValue(9, $evt['notes'], SQLITE3_TEXT); - $res = $stmt->execute(); - if (!$res) die ("Query error: $sql"); // this is unfortunately not very useful -} + print("Fetching last cached wiki event."); + $last_cached_sql = "select cache_id from events where event_type = 'wiki_changed' order by cache_id desc limit 1"; + $res = $dbc->query($last_cached_sql); + if (!$res) die ("Query error: $last_cached_sql"); + $row = $res->fetchArray(SQLITE3_ASSOC); + if (!$row) { + $last_wiki = 0; + } else { + $last_wiki = $row['cache_id']; + } + print(" [$last_wiki]\n"); + + function last_cached_git($repo) { + global $dbc; + $last_cached_sql = "select cache_id from events where event_type='git_commit_$repo' order by event_tstamp desc limit 1"; + $res = $dbc->query($last_cached_sql); + if (!$res) die ("Query error: $last_cached_sql"); + $row = $res->fetchArray(SQLITE3_ASSOC); + if (!$row) { + $last_git = ""; + } else { + $last_git = $row['cache_id']; + } + return $last_git; + } + + + /* gitea issues */ + + print("\nProcessing gitea issues events.\n"); + + $pgdbc = pg_connect("host={$dbhost} dbname={$dbname} user={$dbuser} password={$dbpass}") + or die ("Failed to connect to database: ". pg_last_error()); + + // get issues + $query = 'SELECT i.id, i.repo_id, r.owner_name, r.name AS repo_name, i.index, i.is_closed, i.name, u.full_name, i.created_unix, i.updated_unix, i.closed_unix FROM issue AS i JOIN "user" AS u ON i.poster_id = u.id JOIN repository AS r ON r.id = i.repo_id WHERE r.is_private = false'; + $result = pg_query($query) + or die ("Failed to execute issues query: " . pg_last_error()); + + $events = array(); + while ($row = pg_fetch_array($result, null, PGSQL_ASSOC)) { + + // construct date/time from unix timestamp + $date_im = date_create_immutable_from_format("U", $row['created_unix'], $tz)->setTimezone($tz); + $date = date_format($date_im, 'Y-m-d'); + $time = date_format($date_im, 'H:i'); + + // construct issue URL + $issue_url = $base_url . "/" . $row['owner_name'] . "/" . $row['repo_name'] . "/issues/" . $row['index']; + + // construct wiki user + $user = $row['full_name']; + $userlink = $user; + if (array_key_exists($user, $git_username_map)) { + $wikiname = $git_username_map[$user]; + $userlink = "[[~{$wikiname}|{$user}]]"; + } + + // construct the array wanted by the cacher database schema + $events[] = array( + "cache_id" => $row['created_unix'], + "tstamp" => $row['created_unix'], + "icon" => "task_opened", + "date" => $date, + "time" => $time, + "user" => $user, + "url" => $issue_url, + "description" => "New issue [[ {$issue_url} | {$row['owner_name']}/{$row['repo_name']} #{$row['index']} ]] opened by {$userlink}", + "notes" => $row['name'] + ); + } + + + // get comments/events (gitea combines them) + $query = 'SELECT c.id, c.issue_id, r.owner_name, r.name AS repo_name, i.index, c.type, c.poster_id, u.full_name, c.created_unix, c.updated_unix, (select c.updated_unix = c.created_unix) AS orig, c.content, c.commit_sha FROM comment AS c LEFT JOIN "user" AS u ON u.id = c.poster_id LEFT JOIN issue AS i ON i.id = c.issue_id LEFT JOIN repository AS r ON r.id = i.repo_id WHERE r.is_private = false'; + $result = pg_query($query) + or die ("Failed to execute comments query: " . pg_last_error()); + + //$comments = array(); + while ($row = pg_fetch_array($result, null, PGSQL_ASSOC)) { + + // construct date/time from unix timestamp + $date_im = date_create_immutable_from_format("U", $row['created_unix'], $tz)->setTimezone($tz); + $date = date_format($date_im, 'Y-m-d'); + $time = date_format($date_im, 'H:i'); + + // construct issue URL + $issue_url = $base_url . '/' . $row['owner_name'] . '/' . $row['repo_name'] . '/issues/' . $row['index']; + + // construct wiki user + $user = $row['full_name']; + $userlink = $user; + if (array_key_exists($user, $git_username_map)) { + $wikiname = $git_username_map[$user]; + $userlink = "[[~{$wikiname}|{$user}]]"; + } + + // determine the message (description) by the comment type (https://github.com/go-gitea/gitea/blob/main/models/issues/comment.go#L60) + $desc = ''; + switch ($row['type']) { + case 0: // comment + $desc = "{$userlink} commented on issue [[ {$issue_url} | {$row['owner_name']}/{$row['repo_name']} #{$row['index']} ]]"; + break; + case 4: // referenced by commit + $shortsha = substr($row['commit_sha'], 0, 7); + $desc = "{$userlink} referenced issue [[ {$issue_url} | {$row['owner_name']}/{$row['repo_name']} #{$row['index']} ]] in commit [[ {$base_url}/{$row['owner_name']}/{$row['repo_name']}/commit/{$row['commit_sha']} | {$shortsha} ]]"; + break; + case 7: // labels changed + $desc = "{$userlink} changed label(s) on issue [[ {$issue_url} | {$row['owner_name']}/{$row['repo_name']} #{$row['index']} ]]"; + break; + case 9: // assignees changed + $desc = "{$userlink} changed assignee(s) on issue [[ {$issue_url} | {$row['owner_name']}/{$row['repo_name']} #{$row['index']} ]]"; + break; + case 28: // PR merge + $desc = "{$userlink} merged a pull request for issue [[ {$issue_url} | {$row['owner_name']}/{$row['repo_name']} #{$row['index']} ]]"; + break; + case 2: // close comment + case 29: // PR head branch push + default: + $desc = "{$userlink} modified issue [[ {$issue_url} | {$row['owner_name']}/{$row['repo_name']} #{$row['index']} ]]"; + break; + } + + // construct the array wanted by the cacher database schema + $events[] = array( + 'cache_id' => $row['created_unix'], + 'tstamp' => $row['created_unix'], + 'icon' => 'task_changed', + 'date' => $date, + 'time' => $time, + 'user' => $user, + 'url' => $issue_url, + 'description' => $desc, + 'notes' => '' + ); + } + + + // get closures (this is just a list of all issues with status closed in non-private repos) + $query = 'SELECT c.id, c.type, c.issue_id, i.repo_id, i.index, r.owner_name, r.name as repo_name, u.full_name, i.closed_unix FROM comment AS c JOIN issue AS i ON c.issue_id = i.id JOIN repository AS r ON r.id = i.repo_id JOIN "user" AS u ON c.poster_id = u.id WHERE c.type = 2 AND r.is_private = false'; + $result = pg_query($query) + or die ("Failed to execute closures query: " . pg_last_Error()); + + while ($row = pg_fetch_array($result, null, PGSQL_ASSOC)) { + + // construct date/time from unix timestamp + $date_im = date_create_immutable_from_format("U", $row['closed_unix'], $tz)->setTimezone($tz); + $date = date_format($date_im, 'Y-m-d'); + $time = date_format($date_im, 'H:i'); + + // construct issue URL + $issue_url = $base_url . '/' . $row['owner_name'] . '/' . $row['repo_name'] . '/issues/' . $row['index']; + + // construct wiki user + $user = $row['full_name']; + $userlink = $user; + if (array_key_exists($user, $git_username_map)) { + $wikiname = $git_username_map[$user]; + $userlink = "[[~{$wikiname}|{$user}]]"; + } + + // construct the array wanted by the cacher database schema + $events[] = array( + 'cache_id' => $row['closed_unix'], + 'tstamp' => $row['closed_unix'], + 'icon' => 'task_closed', + 'date' => $date, + 'time' => $time, + 'user' => $user, + 'url' => $issue_url, + "description" => "{$userlink} closed issue [[ {$issue_url} | {$row['owner_name']}/{$row['repo_name']} #{$row['index']} ]]", + 'notes' => '' + ); + } + + + // cleanup + pg_free_result($result); + pg_close($pgdbc); + + + /****************** PmWiki events *********************/ + + print("\nProcessing wiki events.\n"); + + $lines = file($wiki_file); + $chline = ""; + foreach ($lines as $line) { + $line = urldecode($line); + if (substr($line,0,5) == "text=") { + $chline = substr($line,7); + } + } + + if ($chline != "") { + $wikiedits = explode("*", $chline); + $icon = "wiki_changed"; + foreach ($wikiedits as $ed) { + preg_match('/\[\[.*\]\] ./', $ed, $matches); + $page = $matches[0]; + preg_match('/by \[\[.*\]\]/', $ed, $matches); + if (sizeof($matches) != 0) { + $user = $matches[0]; + } else { + $user = "unknown"; + } + preg_match("/\=(.*)\=/s",$ed,$matches); + $notes = $matches[1]; + preg_match("/\. \. \. (.*?) by/s",$ed,$matches); + $date = $matches[1]; + $date = str_replace(", at", "", $date); // old entry format + $tstamp = strtotime($date); + preg_match('/(..\:..)/',$date,$matches); + $time = $matches[0]; + $date = date("Y-m-d", $tstamp); + $action = "?action=diff#" . urlencode($date . " " . $time) . "|diff"; + $page_diff = trim(str_replace("]]", $action."]]", $page)); + preg_match('/\[\[(.*)\|diff\]\]/', $page_diff, $matches); + $url = $matches[1]; + $url = "https://crux.nu/".str_replace(".","/", $url); + $description = "Wiki page $page edited $user ($page_diff)"; + if ($tstamp > $last_wiki) { + $events[] = array( 'cache_id' => $tstamp, 'tstamp' => $tstamp, 'icon' => $icon, 'date' => $date, + 'time' => $time, 'user' => $user, 'url' => $url, 'description' => $description, 'notes' => $notes); + } + //print_r($events); + } + } + + /******************* Git events ***********************/ + + print("\nProcessing git events.\n"); + + foreach ($git_repos as $repo) { + $branch = ""; + if (strpos($repo, ":") !== FALSE) { + $tmp = explode(':', $repo); + $repo = $tmp[0]; + $branch = $tmp[1]; + } + $pos = strpos($repo, "/"); + $reponame = substr($repo, $pos+1); + $last_git = last_cached_git($reponame); + print("Last cached commit for $repo: $last_git\n"); + $out = array(); + $res = 0; + $done = array(); + exec("GIT_DIR=$git_root/$repo.git git log -n 1 $branch", $out, $res); + $git_latest = trim(str_replace("commit ", "", $out[0])); + unset($out); + $res = 0; + if ($git_latest != $last_git) { + if ($last_git == "") { + exec("GIT_DIR=$git_root/$repo.git git log $branch", $out, $res); + } else { + exec("GIT_DIR=$git_root/$repo.git git log $last_git..$git_latest $branch", $out, $res); + } + $last_git = $git_latest; + foreach ($out as $line) { + if (substr($line, 0, 7) == "commit ") { + $rev = substr($line, 7); + $url = sprintf($git_url, $repo, $rev); + $compact_rev = substr($rev,0,4)."..".substr($rev,-4,4); + $revurl = "[[$url|$compact_rev]]"; + } else if (substr($line, 0, 7) == "Merge: ") { + } else if (substr($line, 0, 8) == "Author: ") { + $user = substr($line, 8); + $pos = strpos($user, "<"); + if ($pos !== FALSE) + $user = trim(substr($user,0,$pos)); + if (array_key_exists($user, $git_username_map)) { + $wikiname = $git_username_map[$user]; + $user = "[[~" . $wikiname . "|" . $user . "]]"; + } + $description = "$revurl committed by $user"; + } else if (substr($line, 0, 8) == "Date: ") { + $date = substr($line, 8); + $tstamp = strtotime($date); + $date = date("Y-m-d", $tstamp); + $time = date("H:i", $tstamp); + } else if (trim($line) != "" && !array_key_exists($rev, $done)) { + $icon = "git_commit_$reponame"; + $notes = trim($line); + $events[] = array( 'cache_id' => $rev, 'tstamp' => $tstamp, 'icon' => $icon, 'date' => $date, + 'time' => $time, 'user' => $user, 'url'=>$url, 'description' => $description, 'notes' => $notes); + $done[$rev] = 1; + } + } + } + } + + /*************** Finally, all events *********************/ + $sql = 'INSERT INTO events VALUES (NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; + foreach ($events as $evt) { + $stmt = $dbc->prepare($sql); + $stmt->bindValue(1, $evt['cache_id'], SQLITE3_TEXT); + $stmt->bindValue(2, $evt['tstamp'], SQLITE3_INTEGER); + $stmt->bindValue(3, $evt['icon'], SQLITE3_TEXT); + $stmt->bindValue(4, $evt['date'], SQLITE3_TEXT); + $stmt->bindValue(5, $evt['time'], SQLITE3_TEXT); + $stmt->bindValue(6, $evt['user'], SQLITE3_TEXT); + $stmt->bindValue(7, $evt['url'], SQLITE3_TEXT); + $stmt->bindValue(8, $evt['description'], SQLITE3_TEXT); + $stmt->bindValue(9, $evt['notes'], SQLITE3_TEXT); + $res = $stmt->execute(); + if (!$res) die ("Query error: $sql"); // this is unfortunately not very useful + } + + // vim: set ts=4 et: ?>