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.
Commit 823f8f1ff43c8db148d2b642da87ac10dc67543e

Improved diff output (copy/rename/etc.)
Author: Catalin(ux) M. BOIE
Author date (UTC): 2015-02-14 22:38
Committer name: Catalin(ux) M. BOIE
Committer date (UTC): 2015-02-14 22:38
Parent(s): f794575c600cb52f12a406bf1945966b573c6209
Signing key:
Tree: 45434e087d847db106b85dc3870c0acc5e79e092
File Lines added Lines deleted
README 1 1
TODO 23 8
admin/init.php 10 9
inc/bug.inc.php 41 28
inc/git.inc.php 177 80
inc/repo.inc.php 10 6
inc/rights.inc.php 4 0
inc/user/repo-page.php 8 8
inc/util.inc.php 3 1
root/index.php 2 0
root/robots.txt 3 0
root/themes/default/index.html 1 1
root/themes/default/repo/fstat/header.html 0 1
root/themes/default/repo/log/header.html 0 3
root/themes/default/repo/log/line.html 0 3
scripts/remote.php 11 4
tests/git_log1.php 29 0
tests/git_log1.sh 54 0
tests/git_log1.tmpl 1 0
File README changed (mode: 100644) (index 4aad5e3..396618e)
3 3 . Author: Catalin(ux) M. BOIE . Author: Catalin(ux) M. BOIE
4 4 . Description: Light and fast Git hosting solution . Description: Light and fast Git hosting solution
5 5 . License: GPLv3 . License: GPLv3
6 . Language: PHP (plans to rewrite in C)
6 . Language: PHP (plans to rewrite in C after official release)
7 7 . Database: PostgreSQL . Database: PostgreSQL
8 8
9 9
File TODO changed (mode: 100644) (index a9b6c99..720c2b6)
3 3 Find a way to distribute this code and a way to support it in rg. Find a way to distribute this code and a way to support it in rg.
4 4 Probably I will allow only one plan (Friends) till they all create Probably I will allow only one plan (Friends) till they all create
5 5 accounts. After this, I will remove this plan? accounts. After this, I will remove this plan?
6 [ ] Mail-ul nu vine corect (embedromix.ro)
7 [ ] AVC-uri, probabil ca la scrierea authorized_file
8 6 [ ] In mail-ul phase1, ar trebui adaugata si misiunea acestui proiect. [ ] In mail-ul phase1, ar trebui adaugata si misiunea acestui proiect.
9 [ ] Se pare ca nu se regenereaza authorized_keys file!
10 [ ] Se pare ca event.php nu reactioneaza corect la signaling.
11 Pare ca nu reactioneaza la o inserare de cheie, cu toate ca insert
12 se face in baza de date. Se pare ca fac commit dupa signaling...
13 In plus, tot apare rahatul cu broken pipe!
7 Eventual un FAQ care sa contina si cum vom sustine acest proiect
8 din punct de vedere financiar.
9 [ ] Admin section is not working!
10 [ ] "Running since" apare cu "?"! Rezolvat, dar se pare ca cache-uim raspunsuri
11 negative de la cache daemon. Vrem asta?!
12 [ ] Nu pot sa adaug bug-uri (nu apare form-ul si nici hint-urile)!
13 [ ] Se pare ca sesiunea expira, indifierent daca e activa (apas butoane)!
14 [ ] authorized_keys is missing from 'state' table. Is normal?
15 [ ] 'first_install' is not present in 'state' table.
16 [ ] Move into cron the duty for setting first_install and install_id!
17 Maybe other stuff also.
18 [ ] Seems I cache not set values: first_install is still "?"!
19 [ ] Drop OUTPUT to prevent some attacks? Document in README?
20 [ ] git_diff2array is not parsing correctly the diff --git header.
21 [ ] Fix rg_git_diff to take in consideration last flags and fields from
22 diff2array.
14 23 [ ] [ ]
15 24
16 25 == BEFORE NEXT RELEASE == == BEFORE NEXT RELEASE ==
26 [ ] Replace -=ROCKETGIT=- with a random generated code.
27 [ ] La mail-ul de creare repo, las prea mult spatiu intre "Hello!" si "Repo is".
28 [ ] Seems I cannot reliable kill cache.php. It becomes a zombie!
17 29 [ ] Permisiile pentru /home/rocketgit/.ssh nu sint corecte! Sint root! [ ] Permisiile pentru /home/rocketgit/.ssh nu sint corecte! Sint root!
18 Rezolvat cu chow. Poate vreau sa nu mai rulez cua root keys_regen.
30 Rezolvat cu chown. Poate vreau sa nu mai rulez cua root keys_regen.
31 Only add the regen event! Why? At start we have no users and the first
32 key added will generate a trigger.
33 May be other places where I run as root!
19 34 [ ] Logged in as admin, Admin -> Plans is not working (redirects to main page)! [ ] Logged in as admin, Admin -> Plans is not working (redirects to main page)!
20 35 [ ] init.php: do not show the password! [ ] init.php: do not show the password!
21 36 Maybe switch to a web based instalation? Maybe switch to a web based instalation?
File admin/init.php changed (mode: 100644) (index 16f3e72..6fdb06b)
... ... if ($r !== TRUE) {
36 36 exit(1); exit(1);
37 37 } }
38 38
39 // Store the timestamp of the first install
40 $first_install = rg_state_get($db, "first_install");
41 if ($first_install == 0)
42 rg_state_set($db, "first_install", time());
43
44 $install_id = rg_state_get($db, "install_id");
45 if (empty($install_id))
46 rg_state_set($db, "install_id", sha512(microtime(TRUE)));
47
48
39 49 // creating admin user // creating admin user
40 50 $_u = array(); $_u = array();
41 51 $_u['uid'] = 0; $_u['uid'] = 0;
 
... ... while (1) {
87 97 } }
88 98
89 99
90 // Store the timestamp of the first install
91 $first_install = rg_state_get($db, "first_install");
92 if ($first_install == 0)
93 rg_state_set($db, "first_install", time());
94
95 $install_id = rg_state_get($db, "install_id");
96 if (empty($install_id))
97 rg_state_set($db, "install_id", sha512(microtime(TRUE)));
98
99 100 echo "Done!\n"; echo "Done!\n";
100 101 ?> ?>
File inc/bug.inc.php changed (mode: 100644) (index a4e6963..c06caed)
... ... function rg_bug_vars()
287 287 */ */
288 288 function rg_bug_cosmetic($db, &$row) function rg_bug_cosmetic($db, &$row)
289 289 { {
290 $_ui = rg_user_info($db, $row['uid'], "", "");
291 if ($_ui['exists'] != 1)
292 $row['owner'] = "?";
293 else
294 $row['owner'] = $_ui['username'];
295
296 $row['HTML:body'] = nl2br($row['body']);
297 $row['creation'] = gmdate("Y-m-d H:i", $row['itime']);
298
299 if ($row['utime'] > 0)
300 $row['updated'] = gmdate("Y-m-d H:i", $row['utime']);
301 else
302 $row['updated'] = "-";
303
304 $row['assigned_to'] = "";
305 if ($row['assigned_uid'] > 0) {
306 $_ui = rg_user_info($db, $row['assigned_uid'], "", "");
307 if ($_ui['exists'] == 1)
308 $row['assigned_to'] = $_ui['username'];
290 if (isset($row['uid'])) {
291 $_ui = rg_user_info($db, $row['uid'], "", "");
292 if ($_ui['exists'] != 1)
293 $row['owner'] = "?";
294 else
295 $row['owner'] = $_ui['username'];
296 }
297
298 if (isset($row['body']))
299 $row['HTML:body'] = nl2br($row['body']);
300
301 if (isset($row['itime']))
302 $row['creation'] = gmdate("Y-m-d H:i", $row['itime']);
303
304 if (isset($row['utime'])) {
305 if ($row['utime'] > 0)
306 $row['updated'] = gmdate("Y-m-d H:i", $row['utime']);
307 else
308 $row['updated'] = "-";
309 309 } }
310 310
311 $row['deleted_text'] = "";
312 $row['deleted_who_name'] = "";
313 if (isset($row['deleted_who']) && ($row['deleted_who'] > 0)) {
314 $_ui = rg_user_info($db, $row['deleted_who'], "", "");
315 if ($_ui['exists'] == 1)
316 $row['deleted_who_name'] = $_ui['username'];
311 if (isset($row['assigned_uid'])) {
312 $row['assigned_to'] = "";
313 if ($row['assigned_uid'] > 0) {
314 $_ui = rg_user_info($db, $row['assigned_uid'], "", "");
315 if ($_ui['exists'] == 1)
316 $row['assigned_to'] = $_ui['username'];
317 }
318 }
317 319
318 $row['deleted_text'] = gmdate("Y-m-d H:i", $row['deleted']);
320 if (isset($row['deleted'])) {
321 $row['deleted_text'] = "";
322 $row['deleted_who_name'] = "";
323 if (isset($row['deleted_who']) && ($row['deleted_who'] > 0)) {
324 $_ui = rg_user_info($db, $row['deleted_who'], "", "");
325 if ($_ui['exists'] == 1)
326 $row['deleted_who_name'] = $_ui['username'];
327
328 $row['deleted_text'] = gmdate("Y-m-d H:i", $row['deleted']);
329 }
319 330 } }
320 331
321 $row['state_text'] = rg_bug_state($row['state']);
332 if (isset($row['state']))
333 $row['state_text'] = rg_bug_state($row['state']);
322 334 } }
323 335
324 336 /* /*
 
... ... function rg_bug_edit($db, $login_ui, $ri, $data)
444 456 $data['ip'] = $ip; $data['ip'] = $ip;
445 457 $data['repo_id'] = $ri['repo_id']; $data['repo_id'] = $ri['repo_id'];
446 458 $data['uid'] = $login_ui['uid']; $data['uid'] = $login_ui['uid'];
459 $data['deleted'] = 0;
447 460 if ($add == 1) { if ($add == 1) {
448 461 $sql = "INSERT INTO bugs (bug_id, itime, utime, repo_id" $sql = "INSERT INTO bugs (bug_id, itime, utime, repo_id"
449 462 . ", uid, ip, title, body, state, assigned_uid" . ", uid, ip, title, body, state, assigned_uid"
450 463 . ", deleted)" . ", deleted)"
451 464 . " VALUES (@@bug_id@@, @@itime@@, 0, @@repo_id@@" . " VALUES (@@bug_id@@, @@itime@@, 0, @@repo_id@@"
452 465 . ", @@uid@@, @@ip@@, @@title@@, @@body@@" . ", @@uid@@, @@ip@@, @@title@@, @@body@@"
453 . ", @@state@@, @@assigned_uid@@, 0)";
466 . ", @@state@@, @@assigned_uid@@, @@deleted@@)";
454 467 } else { } else {
455 468 $sql = "UPDATE bugs SET utime = @@itime@@" $sql = "UPDATE bugs SET utime = @@itime@@"
456 469 . ", title = @@title@@" . ", title = @@title@@"
File inc/git.inc.php changed (mode: 100644) (index 7165cb0..cd78d8e)
... ... function rg_git_ls_tree($tree, $path)
454 454 /* /*
455 455 * Transforms a diff into an array (ready for rg_git_diff) * Transforms a diff into an array (ready for rg_git_diff)
456 456 */ */
457 function rg_git_diff2array($diff)
457 function rg_git_diff2array($diff, &$extra)
458 458 { {
459 459 rg_prof_start("git_diff2array"); rg_prof_start("git_diff2array");
460 //rg_log_ml("DEBUG: git_diff2array: diff: " . $diff);
460 461
461 462 $ret = array(); $ret = array();
462 463
464 $extra['lines_add'] = 0;
465 $extra['lines_del'] = 0;
466
463 467 $lines = explode("\n", $diff); $lines = explode("\n", $diff);
468 //rg_log_ml("DEBUG: lines: " . print_r($lines, TRUE));
464 469
465 $file = 0;
470 $file = -1;
466 471 foreach ($lines as $line) { foreach ($lines as $line) {
467 if (strncmp($line, "diff ", 5) == 0) {
472 //rg_log("DEBUG: line=$line");
473
474 // format: diff --git a/a b/a
475 if (strncmp($line, "diff --git ", 11) == 0) {
468 476 $file++; $file++;
469 477 $ret[$file] = array(); $ret[$file] = array();
470 478 $ret[$file]['flags'] = ""; $ret[$file]['flags'] = "";
479 $ret[$file]['old_mode'] = "";
480 $ret[$file]['mode'] = "";
481 $ret[$file]['similarity'] = "";
482 $ret[$file]['dissimilarity'] = "";
483 $ret[$file]['lines_add'] = 0;
484 $ret[$file]['lines_del'] = 0;
485
486 $rest = substr($line, 11);
487 //rg_log("DEBUG: rest=$rest.");
488 $rest = str_replace('" "', ' ', $rest);
489 $rest = trim($rest, '"');
490 $rest = substr($rest, 2); /* skip 'a/' */
491 $_t = explode(' b/', $rest);
492 foreach ($_t as &$_file) {
493 if (strncmp($_file, '"', 1) == 0)
494 $_file = substr($_file, 1, -1);
495 $_file = str_replace('\"', '"', $_file);
496 }
497 $ret[$file]['file_from'] = $_t[0];
498 $ret[$file]['file'] = $_t[1];
499 $ret[$file]['index'] = "";
471 500 $ret[$file]['chunks'] = array(); $ret[$file]['chunks'] = array();
472 $file_name_sel = "dst";
473 $file_name_tmp = array();
474 501 continue; continue;
475 502 } }
476 503
477 if (strncmp($line, "new file ", 9) == 0) {
478 $ret[$file]['flags'] .= "N";
504 if (strncmp($line, "old mode ", 9) == 0) {
505 $ret[$file]['old_mode'] = substr($line, 9);
479 506 continue; continue;
480 507 } }
481 508
482 if (strncmp($line, "deleted file ", 13) == 0) {
509 if (strncmp($line, "new mode ", 9) == 0) {
510 $ret[$file]['mode'] = substr($line, 9);
511 continue;
512 }
513
514 if (strncmp($line, "deleted file mode ", 18) == 0) {
483 515 $ret[$file]['flags'] .= "D"; $ret[$file]['flags'] .= "D";
484 $file_name_sel = "src";
516 $ret[$file]['old_mode'] = substr($line, 18);
485 517 continue; continue;
486 518 } }
487 519
488 if (strncmp($line, "index ", 6) == 0) {
489 $ret[$file]['index'] = substr($line, 6);
520 if (strncmp($line, "new file mode ", 14) == 0) {
521 $ret[$file]['flags'] .= "N";
522 $ret[$file]['mode'] = substr($line, 14);
490 523 continue; continue;
491 524 } }
492 525
493 if (strncmp($line, "--- ", 4) == 0) {
494 if (strncmp($line, "--- a/", 2) == 0)
495 $file_name_tmp['src'] = substr($line, 6);
496 else
497 $file_name_tmp['src'] = substr($line, 4);
526 if (strncmp($line, "copy from ", 10) == 0) {
527 $ret[$file]['flags'] .= "C";
498 528 continue; continue;
499 529 } }
500 530
501 if (strncmp($line, "+++ ", 4) == 0) {
502 if (strncmp($line, "+++ b/", 2) == 0)
503 $file_name_tmp['dst'] = substr($line, 6);
504 else
505 $file_name_tmp['dst'] = substr($line, 4);
531 if (strncmp($line, "copy to ", 10) == 0)
532 continue;
533
534 if (strncmp($line, "rename from ", 12) == 0) {
535 $ret[$file]['flags'] .= "R";
536 continue;
537 }
538
539 if (strncmp($line, "rename to ", 10) == 0)
540 continue;
541
542 if (strncmp($line, "similarity index ", 17) == 0) {
543 $ret[$file]['similarity'] = substr($line, 17);
544 continue;
545 }
546
547 if (strncmp($line, "dissimilarity index ", 20) == 0) {
548 $ret[$file]['dissimilarity'] = substr($line, 20);
506 549 continue; continue;
507 550 } }
508 551
552 if (strncmp($line, "index ", 6) == 0) {
553 $rest = substr($line, 6);
554 $_t = explode(' ', $rest);
555 $ret[$file]['index'] = $_t[0];
556 if (isset($_t[1]))
557 $ret[$file]['mode'] = $_t[1];
558 continue;
559 }
560
561 if (strncmp($line, "--- ", 4) == 0)
562 continue;
563
564 if (strncmp($line, "+++ ", 4) == 0)
565 continue;
566
509 567 // parse line "@@ -14,6 +14,8 @@ function..." // parse line "@@ -14,6 +14,8 @@ function..."
510 568 // @@ from_file_range to_file_range @@ ... // @@ from_file_range to_file_range @@ ...
511 if (strncmp($line, "@@ ", 3) == 0) {
569 if (strncmp($line, "@@", 2) == 0) {
570 rg_log("DEBUG: chunks: $line");
571
512 572 $_t = explode(" ", $line, 5); $_t = explode(" ", $line, 5);
513 573 if (count($_t) < 4) { if (count($_t) < 4) {
514 rg_internal_error("invalid line [$line]: count != 5");
574 rg_internal_error("invalid line [$line]: count < 4");
515 575 return FALSE; return FALSE;
516 576 } }
517 577 $chunk = $_t[1] . " " . $_t[2]; $chunk = $_t[1] . " " . $_t[2];
518 578 $ret[$file]['chunks'][$chunk] = array(); $ret[$file]['chunks'][$chunk] = array();
519 579 $ret[$file]['chunks'][$chunk]['section'] = isset($_t[4]) ? trim($_t[4]) : ""; $ret[$file]['chunks'][$chunk]['section'] = isset($_t[4]) ? trim($_t[4]) : "";
520 $from = explode(",", substr($_t[1], 1));
521 $ret[$file]['chunks'][$chunk]['from'] = intval($from[0]);
522 $to = explode(",", substr($_t[2], 1));
523 $ret[$file]['chunks'][$chunk]['to'] = intval($to[0]);
580
581 if (strcmp($_t[1], '-1') == 0) {
582 $from = '1';
583 } else {
584 $from = explode(",", substr($_t[1], 1)); /* split '-14,6'; 1: skip '-' prefix */
585 $from = intval($from[0]);
586 }
587 $ret[$file]['chunks'][$chunk]['from'] = $from;
588
589 if (strcmp($_t[2], '+1') == 0) {
590 $to = '1';
591 } else {
592 $to = explode(",", substr($_t[2], 1)); /* split '+14,8'; 1: skip '+' prefix */
593 $to = intval($to[0]);
594 }
595 $ret[$file]['chunks'][$chunk]['to'] = $to;
524 596 continue; continue;
525 597 } }
526 598
527 if (!isset($file_name_tmp[$file_name_sel])) {
528 rg_internal_error("file_name_tmp[$file_name_sel] does not exists"
529 . "; file_name_tmp: " . print_r($file_name_tmp, TRUE));
530 return FALSE;
599 if (empty($line)) {
600 //rg_log("\tWARN: empty line [$line]!");
601 continue;
531 602 } }
532 603
533 if (!isset($ret[$file]['file']))
534 $ret[$file]['file'] = $file_name_tmp[$file_name_sel];
604 if (strncmp($line, "\0", 1) == 0) {
605 //rg_log("\tWARN: \0 line!");
606 continue;
607 }
535 608
536 // empty is because somehow git log pass an empty line.
537 // TODO: we should check this theory.
538 if (empty($line)
539 || (strncmp($line, " ", 1) == 0)
609 if ((strncmp($line, " ", 1) == 0)
540 610 || (strncmp($line, "+", 1) == 0) || (strncmp($line, "+", 1) == 0)
541 611 || (strncmp($line, "-", 1) == 0)) { || (strncmp($line, "-", 1) == 0)) {
542 612 $ret[$file]['chunks'][$chunk]['lines'][] = $line; $ret[$file]['chunks'][$chunk]['lines'][] = $line;
613
614 if (strncmp($line, '+', 1) == 0) {
615 $ret[$file]['lines_add']++;
616 $extra['lines_add']++;
617 } else if (strncmp($line, '-', 1) == 0) {
618 $ret[$file]['lines_del']++;
619 $extra['lines_del']++;
620 }
621
543 622 continue; continue;
544 623 } }
545 624
 
... ... function rg_git_diff2array($diff)
549 628 continue; continue;
550 629 } }
551 630
552 if (empty($line)) {
553 rg_log("\tWARN: empty line [$line]!");
554 continue;
555 }
556
557 631 rg_internal_error("I do not know how to parse [" . trim($line) . "]!"); rg_internal_error("I do not know how to parse [" . trim($line) . "]!");
558 632 $ret = FALSE; $ret = FALSE;
633 break;
559 634 } }
560 635
561 636 rg_prof_end("git_diff2array"); rg_prof_end("git_diff2array");
 
... ... function rg_git_diff2array($diff)
565 640 /* /*
566 641 * Show last @max commits, no merges, sort by topo * Show last @max commits, no merges, sort by topo
567 642 * @also_patch = TRUE if caller needs also the patch * @also_patch = TRUE if caller needs also the patch
643 * TODO: $also_merges: remove --no-merges
568 644 */ */
569 645 function rg_git_log($path, $max, $from, $to, $also_patch) function rg_git_log($path, $max, $from, $to, $also_patch)
570 646 { {
 
... ... function rg_git_log($path, $max, $from, $to, $also_patch)
594 670 $cmd = "git --no-pager" $cmd = "git --no-pager"
595 671 . " --git-dir=" . escapeshellarg($path) . " --git-dir=" . escapeshellarg($path)
596 672 . " log" . " log"
673 . " --find-copies"
597 674 . " --no-merges" . " --no-merges"
598 675 . " -z" . " -z"
599 676 . $max_count . $max_count
 
... ... function rg_git_log($path, $max, $from, $to, $also_patch)
616 693 . "body:%b%x00\"\"" . "body:%b%x00\"\""
617 694 . "notes:%N%x00\"\"" . "notes:%N%x00\"\""
618 695 . "%x00ROCKETGIT_END_OF_VARS%x00\"" . "%x00ROCKETGIT_END_OF_VARS%x00\""
619 . " --numstat"
620 696 . $from_to; . $from_to;
621 697 $a = rg_exec($cmd); $a = rg_exec($cmd);
622 698 if ($a['ok'] != 1) { if ($a['ok'] != 1) {
 
... ... function rg_git_log($path, $max, $from, $to, $also_patch)
625 701 break; break;
626 702 } }
627 703
628 // we prepend a \0 because data starts with -=ROCK...
704 //rg_log_ml("DEBUG: OUTPUT OF GIT LOG: " . $a['data']);
705
706 // because data starts with -=ROCK..., we remove it
707 $a['data'] = substr($a['data'], 14);
629 708 $blocks = explode("\0-=ROCKETGIT=-\0", "\0" . $a['data']); $blocks = explode("\0-=ROCKETGIT=-\0", "\0" . $a['data']);
630 // ignore first entry because is empty
631 unset($blocks[0]);
632 709
633 710 $ret = array(); $ret = array();
634 711 foreach ($blocks as $junk => $block) { foreach ($blocks as $junk => $block) {
635 $y = array("vars" => array(), "files" => array(), "patches" => array());
712 $y = array("vars" => array(), "files" => array());
636 713
637 // split block in two: vars and stats + patches
714 // split block in two: vars and patches
638 715 $parts = explode("\0ROCKETGIT_END_OF_VARS\0", $block, 2); $parts = explode("\0ROCKETGIT_END_OF_VARS\0", $block, 2);
639 716
640 717 // vars // vars
718 $y['vars']['lines_add'] = 0;
719 $y['vars']['lines_del'] = 0;
641 720 $x = explode ("\0", trim($parts[0])); $x = explode ("\0", trim($parts[0]));
642 721 $count = count($x); $count = count($x);
643 722 for ($i = 0; $i < $count - 1; $i++) { for ($i = 0; $i < $count - 1; $i++) {
644 723 $_t = explode(":", $x[$i], 2); $_t = explode(":", $x[$i], 2);
645 if (isset($_t[1]))
724 if (isset($_t[1])) {
646 725 $y['vars'][$_t[0]] = trim($_t[1]); $y['vars'][$_t[0]] = trim($_t[1]);
647 else
648 echo "Var " . $_t[0] . " has no value!\n";
726 } else if (empty($_t[0])) {
727 // do nothing
728 } else {
729 rg_log("DEBUG: Var [" . $_t[0] . "] has no value!");
730 }
649 731 } }
650 732
651 // stats & patches
652 $stats_and_patches = trim($parts[1]);
653 $_sp = explode("\0\0", $stats_and_patches, 2);
654 $stats = $_sp[0];
655 if (isset($_sp[1])) {
656 $y['patches'] = rg_git_diff2array($_sp[1]);
657 if ($y['patches'] === FALSE)
733 // patches
734 if (isset($parts[1])) {
735 $y['files'] = rg_git_diff2array($parts[1], $_extra);
736 if ($y['files'] === FALSE)
658 737 break; break;
659 }
660 738
661 // stats
662 $_t = explode("\0", $stats);
663 $y['vars']['files_changed'] = count($_t);
664 $total_add = 0;
665 $total_del = 0;
666 foreach ($_t as $junk => $fi) {
667 $__t = explode("\t", $fi);
668 $y['files'][$__t[2]] = array(
669 "add" => $__t[0],
670 "del" => $__t[1]);
671 $total_add += intval($__t[0]);
672 $total_del += intval($__t[1]);
739 $y['vars']['lines_add'] = $_extra['lines_add'];
740 $y['vars']['lines_del'] = $_extra['lines_del'];
673 741 } }
674 $y['vars']['lines_add'] = $total_add;
675 $y['vars']['lines_del'] = $total_del;
676 742
677 743 // final additions // final additions
678 744 $y['vars']['author date UTC'] = gmdate("Y-m-d H:i:s", $y['vars']['author date']); $y['vars']['author date UTC'] = gmdate("Y-m-d H:i:s", $y['vars']['author date']);
 
... ... function rg_git_files($old, $new)
802 868 /* /*
803 869 * Nice diff per file * Nice diff per file
804 870 * Outputs the result of replacing variables in a template with real variables * Outputs the result of replacing variables in a template with real variables
805 * @a - output of rg_git_diff2array[index]
871 * @a - output of rg_git_diff2array[index]['files']
806 872 * TODO: Switch to rg_template_table? * TODO: Switch to rg_template_table?
807 873 */ */
808 874 function rg_git_diff($a, $template_file) function rg_git_diff($a, $template_file)
 
... ... function rg_git_diff($a, $template_file)
820 886 if (!isset($finfo['file'])) if (!isset($finfo['file']))
821 887 rg_log("BAD finfo:" . rg_array2string($finfo)); rg_log("BAD finfo:" . rg_array2string($finfo));
822 888
889 rg_log_ml("DEBUG: finfo: " . print_r($finfo, TRUE));
890
823 891 $ret .= "<br />\n"; $ret .= "<br />\n";
824 892
825 893 $f = rg_xss_safe($finfo['file']); $f = rg_xss_safe($finfo['file']);
 
... ... function rg_git_diff($a, $template_file)
830 898 if (strstr($finfo['flags'], "N")) if (strstr($finfo['flags'], "N"))
831 899 $ret .= "File <b>$f</b> added"; $ret .= "File <b>$f</b> added";
832 900 else if (strstr($finfo['flags'], "D")) else if (strstr($finfo['flags'], "D"))
833 $ret .= "File <b>$f</b> deleted:";
901 $ret .= "File <b>$f</b> deleted";
902 else if (strstr($finfo['flags'], "C"))
903 $ret .= "File <b>$f</b> copied from "
904 . rg_xss_safe($finfo['file_from']);
905 else if (strstr($finfo['flags'], "R"))
906 $ret .= "File <b>$f</b> renamed from "
907 . rg_xss_safe($finfo['file_from']);
834 908 else else
835 $ret .= "File <b>$f</b> changed:";
909 $ret .= "File <b>$f</b> changed";
910
911 if (!empty($finfo['similarity']))
912 $ret .= " (similarity " . rg_xss_Safe($finfo['similarity']) . ")";
913
914 if (!empty($finfo['dissimilarity']))
915 $ret .= " (dissimilarity " . rg_xss_safe($finfo['dissimilarity']) . ")";
916
917 if (!empty($finfo['mode'])) {
918 $ret .= " (mode: " . rg_xss_safe($finfo['mode']);
919 if (!empty($finfo['old_mode']))
920 $ret .= " -&gt; " . rg_xss_safe($finfo['old_mode']);
921 $ret .= ")";
922 }
923
924 if (!empty($finfo['index']))
925 $ret .= " (index " . rg_xss_safe($finfo['index']) . ")";
926
927 // TODO: Before stats we must show commit hash, author etc. (source/log/commit/xxxxxx)
928 // TODO: what about commiter and time and rest?
929
930 $ret .= ":";
836 931 $ret .= "</td></tr>\n"; $ret .= "</td></tr>\n";
837 932
838 933 $empty_line = ""; $empty_line = "";
839 934 foreach ($finfo['chunks'] as $chunk => $ci) { foreach ($finfo['chunks'] as $chunk => $ci) {
935 //rg_log_ml("DEBUG: ci: " . print_r($ci, TRUE));
840 936 $ret .= $empty_line; $ret .= $empty_line;
841 937 $empty_line = "<tr style=\"border: 1px\"><td colspan=\"4\">&nbsp;</td></tr>\n"; $empty_line = "<tr style=\"border: 1px\"><td colspan=\"4\">&nbsp;</td></tr>\n";
842 938 if (!empty($ci['section'])) { if (!empty($ci['section'])) {
 
... ... function rg_git_diff($a, $template_file)
900 996
901 997 /* /*
902 998 * Show stats for files changed * Show stats for files changed
999 * @a = rg_git_log[0]['files']
903 1000 */ */
904 1001 function rg_git_files_stats($a, $dir) function rg_git_files_stats($a, $dir)
905 1002 { {
906 1003 $t = array(); $t = array();
907 foreach ($a as $file => $info) {
1004 foreach ($a as $index => $info) {
908 1005 $line = array(); $line = array();
909 $line['file'] = $file;
910 $line['add'] = $info['add'];
911 $line['del'] = $info['del'];
1006 $line['file'] = $info['file'];
1007 $line['add'] = $info['lines_add'];
1008 $line['del'] = $info['lines_del'];
912 1009 $t[] = $line; $t[] = $line;
913 1010 } }
914 1011
File inc/repo.inc.php changed (mode: 100644) (index 5017f0c..dfb5451)
... ... function rg_repo_ok($repo)
547 547 } }
548 548
549 549 $len = strlen($repo); $len = strlen($repo);
550 rg_log("CHECK: strlen($repo)=$len");
551 550 if ($len < $rg_repo_min_len) { if ($len < $rg_repo_min_len) {
552 551 rg_repo_set_error("repository name is too short" rg_repo_set_error("repository name is too short"
553 552 . " (minimum $rg_repo_min_len < $len)"); . " (minimum $rg_repo_min_len < $len)");
 
... ... function rg_repo_edit_high_level($db, &$rg)
1416 1415 $errmsg = array(); $errmsg = array();
1417 1416 $load_form = TRUE; $load_form = TRUE;
1418 1417 while (1) { while (1) {
1419 if (($rg['ri']['repo_id'] > 0) && (rg_rights_allow($db, $rg['ri']['repo_id'], "repo", $rg['ri']['uid'],
1418 if ($rg['ri']['repo_id'] > 0)
1419 $edit = TRUE;
1420 else
1421 $edit = FALSE;
1422
1423 if ($edit && (rg_rights_allow($db, $rg['ri']['repo_id'], "repo", $rg['ri']['uid'],
1420 1424 $rg['login_ui']['uid'], "E", $rg['ip'], "") !== TRUE)) { $rg['login_ui']['uid'], "E", $rg['ip'], "") !== TRUE)) {
1421 1425 $ret .= rg_template("user/repo/deny_edit.html", $rg); $ret .= rg_template("user/repo/deny_edit.html", $rg);
1422 1426 $load_form = FALSE; $load_form = FALSE;
 
... ... function rg_repo_edit_high_level($db, &$rg)
1424 1428 } }
1425 1429
1426 1430 if ($rg['doit'] != 1) { if ($rg['doit'] != 1) {
1427 if ($rg['ri']['repo_id'] == 0) {
1431 if (!$edit) {
1428 1432 // Defaults // Defaults
1429 1433 $rg['ri'] = array(); $rg['ri'] = array();
1430 1434 $rg['ri']['repo_id'] = "0"; $rg['ri']['repo_id'] = "0";
 
... ... function rg_repo_edit_high_level($db, &$rg)
1465 1469
1466 1470 $rg['ri']['home'] = rg_re_repopage($rg['login_ui'], $rg['ri']['home'] = rg_re_repopage($rg['login_ui'],
1467 1471 $rg['ri']['name']); $rg['ri']['name']);
1468 if ($rg['ri']['repo_id'] == 0) {
1469 $ret .= rg_template("repo/create_ok.html", $rg);
1470 } else {
1472 if ($edit) {
1471 1473 $ret .= rg_template("repo/edit_ok.html", $rg); $ret .= rg_template("repo/edit_ok.html", $rg);
1474 } else {
1475 $ret .= rg_template("repo/create_ok.html", $rg);
1472 1476 } }
1473 1477
1474 1478 $load_form = FALSE; $load_form = FALSE;
File inc/rights.inc.php changed (mode: 100644) (index 63b09c3..7c93605)
... ... function rg_rights_split_ip($ip)
438 438 $ip2 = $ip; $ip2 = $ip;
439 439 } }
440 440
441 // Deal with ::ffff:46.102.28.148
442 if (strncasecmp($ip2, "::ffff:", 7) == 0)
443 $ip2 = substr($ip2, 7);
444
441 445 if (preg_match('/^[a-fA-F0-9:]*$/D', $ip2)) { /* ipv6 */ if (preg_match('/^[a-fA-F0-9:]*$/D', $ip2)) { /* ipv6 */
442 446 if ($ret['prefix_len'] == -1) { if ($ret['prefix_len'] == -1) {
443 447 $ret['prefix_len'] = 128; $ret['prefix_len'] = 128;
File inc/user/repo-page.php changed (mode: 100644) (index af2b203..6368bb4)
... ... if (strcmp($_subop, "history") == 0) {
165 165 $_repo_body .= rg_warning("Error generating log!"); $_repo_body .= rg_warning("Error generating log!");
166 166 // TODO: rg_internal_error? // TODO: rg_internal_error?
167 167 } else if (empty($log)) { } else if (empty($log)) {
168 $_repo_body .= rg_template("repo/not_init.html",
169 $rg);
168 $_repo_body .= rg_template("repo/not_init.html", $rg);
170 169 } else { } else {
171 //rg_log("DEBUG: log: " . print_r($log, TRUE));
172 $_repo_body .= rg_git_log_template($log,
173 "repo/log", $rg);
170 rg_log_ml("DEBUG: log: " . print_r($log, TRUE));
171 $_repo_body .= rg_git_log_template($log, "repo/log", $rg);
174 172 } }
175 173
176 174 $type = array_shift($paras); $type = array_shift($paras);
 
... ... if (strcmp($_subop, "history") == 0) {
185 183 $first = $t[0]; $first = $t[0];
186 184 $second = $t[1]; $second = $t[1];
187 185 } else { } else {
188 $first = $commit . "~1";
186 $first = "";
189 187 $second = $commit; $second = $commit;
190 188 } }
191 189
190 $_repo_body .= "<br /><b>Commit " . rg_xss_safe($commit) . "</b><br />\n";
191
192 192 $log = rg_git_log($repo_path, 1, $first, $second, TRUE); $log = rg_git_log($repo_path, 1, $first, $second, TRUE);
193 193 if ($log === FALSE) { if ($log === FALSE) {
194 194 $_repo_body .= rg_warning("Could not generate log."); $_repo_body .= rg_warning("Could not generate log.");
 
... ... if (strcmp($_subop, "history") == 0) {
205 205 $_repo_body .= $_r; $_repo_body .= $_r;
206 206
207 207 // diff // diff
208 //rg_log("DEBUG: log[0]['patches']: " . rg_array2string($log[0]['patches']));
209 $_r = rg_git_diff($log[0]['patches'], "repo/diff.html");
208 rg_log("DEBUG: log[0]['files']: " . rg_array2string($log[0]['files']));
209 $_r = rg_git_diff($log[0]['files'], "repo/diff.html");
210 210 //rg_log("DEBUG: git_diff: " . $_r); //rg_log("DEBUG: git_diff: " . $_r);
211 211 if ($_r === FALSE) if ($_r === FALSE)
212 212 rg_internal_error("Could not generate patches" rg_internal_error("Could not generate patches"
File inc/util.inc.php changed (mode: 100644) (index 620aa6f..2012982)
... ... function rg_prepare_replace_helper($a, $prefix, &$what, &$values)
481 481 $v = rg_xss_safe($v); $v = rg_xss_safe($v);
482 482 } }
483 483
484 $what[$new_prefix] = "/@@" . $new_prefix . "@@/uU";
484 $what[$new_prefix] = "/@@" . preg_quote($new_prefix, '/') . "@@/uU";
485 485 $values[$new_prefix] = $v; $values[$new_prefix] = $v;
486 486 } }
487 487 } }
 
... ... function rg_mail($template, $more)
1191 1191 $subject = "=?UTF-8?B?" . base64_encode(trim($subject)) . "?="; $subject = "=?UTF-8?B?" . base64_encode(trim($subject)) . "?=";
1192 1192 $header = rg_template("mail/common.head.txt", $more); $header = rg_template("mail/common.head.txt", $more);
1193 1193 $header .= rg_template($template . ".head.txt", $more); $header .= rg_template($template . ".head.txt", $more);
1194 $header = trim($header);
1194 1195 $body = rg_template($template . ".body.txt", $more); $body = rg_template($template . ".body.txt", $more);
1195 1196
1197 rg_log("CHECK: mail(" . $more['ui.email'] . ", $subject, $body, $header, -f $rg_admin_email");
1196 1198 $ret = mail($more['ui.email'], $subject, $body, $header, "-f $rg_admin_email"); $ret = mail($more['ui.email'], $subject, $body, $header, "-f $rg_admin_email");
1197 1199 if ($ret === FALSE) if ($ret === FALSE)
1198 1200 rg_log("Sending mail failed to=" . $more['ui.email'] . " subject=$subject!"); rg_log("Sending mail failed to=" . $more['ui.email'] . " subject=$subject!");
File root/index.php changed (mode: 100644) (index e051bef..cfc3b5e)
... ... $user = ""; $repo = ""; $organization = 0; // TODO: those are really used?
69 69
70 70 $rg['ua'] = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ""; $rg['ua'] = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : "";
71 71 $rg['ip'] = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : ""; $rg['ip'] = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : "";
72 if (strncasecmp($rg['ip'], "::ffff:", 7) == 0)
73 $rg['ip'] = substr($rg['ip'], 7);
72 74 rg_log("DEBUG: _REQUEST: " . rg_array2string($_REQUEST)); rg_log("DEBUG: _REQUEST: " . rg_array2string($_REQUEST));
73 75 rg_log("DEBUG: _COOKIE: " . rg_array2string($_COOKIE)); rg_log("DEBUG: _COOKIE: " . rg_array2string($_COOKIE));
74 76 rg_log($rg['ip'] . " ver=$rocketgit_version"); rg_log($rg['ip'] . " ver=$rocketgit_version");
File root/robots.txt added (mode: 100644) (index 0000000..d332754)
1 User-agent: *
2 Allow: /
3 Disallow: /nonexisting
File root/themes/default/index.html changed (mode: 100644) (index 8de0437..99c6856)
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1 <!DOCTYPE html>
2 2 <html xmlns="http://www.w3.org/1999/xhtml"> <html xmlns="http://www.w3.org/1999/xhtml">
3 3 <head> <head>
4 4 <title>RocketGit</title> <title>RocketGit</title>
File root/themes/default/repo/fstat/header.html changed (mode: 100644) (index 12a85bd..73eefdd)
1 <br />
2 1 <table> <table>
3 2 <tr> <tr>
4 3 <th>File</th> <th>File</th>
File root/themes/default/repo/log/header.html changed (mode: 100644) (index 92dca71..f7679f2)
5 5 <th>SHA-1</th> <th>SHA-1</th>
6 6 <th>Author</th> <th>Author</th>
7 7 <th>Date</th> <th>Date</th>
8 <th>Files changed</th>
9 <th>Lines added</th>
10 <th>Lines deleted</th>
11 8 </tr> </tr>
File root/themes/default/repo/log/line.html changed (mode: 100644) (index 229426b..30d7b57)
3 3 <td><a href="@@url_repo@@/source/log/commit/@@sha1_short@@">@@sha1_short@@</a></td> <td><a href="@@url_repo@@/source/log/commit/@@sha1_short@@">@@sha1_short@@</a></td>
4 4 <td>@@author name@@ (@@author email@@)</td> <td>@@author name@@ (@@author email@@)</td>
5 5 <td>@@author date UTC@@</td> <td>@@author date UTC@@</td>
6 <td>@@files_changed@@</td>
7 <td>@@lines_add@@</td>
8 <td>@@lines_del@@</td>
9 6 </tr> </tr>
File scripts/remote.php changed (mode: 100644) (index 6a92109..87d4f1d)
... ... if (strcmp($_t[0], "user") == 0) {
162 162
163 163 rg_log("host=[$host] cmd=[$cmd] prefix=[$prefix] user=[$user] repo=[$repo]."); rg_log("host=[$host] cmd=[$cmd] prefix=[$prefix] user=[$user] repo=[$repo].");
164 164
165 // TODO: if $host does not match $rg_git_host, give a warning to the user to
166 // update the config.
167
165 168 // validity/security checks // validity/security checks
166 169 // Load info about the owner // Load info about the owner
167 170 if (rg_user_ok($user) !== TRUE) if (rg_user_ok($user) !== TRUE)
 
... ... if ($owner_ui['ok'] != 1)
172 175 if ($owner_ui['exists'] != 1) if ($owner_ui['exists'] != 1)
173 176 fatal("User does not exists (repo)."); fatal("User does not exists (repo).");
174 177
175 // Load info about the connecting user
176 $conn_ui = rg_user_info($db, $login_uid, "", "");
177 if ($conn_ui['exists'] != 1)
178 fatal("User does not exists (conn).");
178 // Load info about the connecting user, if known
179 if ($login_uid > 0) {
180 $conn_ui = rg_user_info($db, $login_uid, "", "");
181 if ($conn_ui['exists'] != 1)
182 fatal("User does not exists (conn).");
183 } else {
184 $conn_ui = array("uid" => 0);
185 }
179 186
180 187 // Loading info about the repository // Loading info about the repository
181 188 if (rg_repo_ok($repo) !== TRUE) if (rg_repo_ok($repo) !== TRUE)
File tests/git_log1.php added (mode: 100644) (index 0000000..50ed2cd)
1 <?php
2 // This will be run from git_log1.sh
3
4 error_reporting(E_ALL | E_STRICT);
5 ini_set("track_errors", "On");
6
7 $INC = dirname(__FILE__) . "/../inc";
8 require_once(dirname(__FILE__) . "/config.php");
9 require_once($INC . "/init.inc.php");
10 require_once($INC . "/git.inc.php");
11
12 rg_log_set_file(dirname(__FILE__) . "/git_log1.log");
13
14 $rg_no_db = TRUE;
15 require_once("common.php");
16
17 // test rg_log
18 $path = dirname(__FILE__) . "/git_log1/.git";
19 $max = 0;
20 $from = "";
21 $to = "";
22 $also_patch = TRUE;
23 $r = rg_git_log($path, $max, $from, $to, $also_patch);
24 file_put_contents(dirname(__FILE__) . "/git_log1.out", print_r($r, TRUE));
25
26 $a = rg_git_diff($r, "git_log1.tmpl");
27 file_put_contents(dirname(__FILE__) . "/git_log1.final", $a);
28
29 ?>
File tests/git_log1.sh added (mode: 100755) (index 0000000..a01dff6)
1 #!/bin/bash
2
3 set -e
4
5 rm -rf git_log1
6
7 mkdir git_log1
8 cd git_log1
9 git init
10 git remote add origin ssh://rocketgit@ssh.rocketgit.com/user/catalinux/test1
11
12 echo "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" > a
13 git add a
14 git commit -a -m "a"
15
16 # special file that contains '"'
17 touch "xx\"yy"
18 git add "xx\"yy"
19 git commit -a -m "quote file"
20
21 # empty file
22 touch empty.txt
23 git add empty.txt
24 git commit -a -m "commit empty file"
25
26 cp a a2
27 git add a2
28 git commit -a -m "a copied to a2"
29
30 # let's see if we can correcly parse a rename and another operation
31 echo "aaaaaaaaaaaaaaaaaaaa" > c
32 git add c
33 git mv a2 a3
34 git commit -a -m "a2 moved to a3 and added c"
35
36 git rm a3
37 git commit -a -m "a3 removed"
38
39 echo "aaa" > "a b c"
40 git add "a b c"
41 git commit -a -m "\"a b c\" file commited"
42
43 # Try to trigger dissimilarity stuff
44 echo "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" > dis1
45 echo "baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" >> dis1
46 git add dis1
47 git commit -a -m "dis1 commited"
48 echo "baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" > dis1
49 echo "caaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" >> dis1
50 git commit -a -m "dis1 changed"
51
52 php ../git_log1.php
53
54 echo "git_log1: OK"
File tests/git_log1.tmpl added (mode: 100644) (index 0000000..ac310b4)
1 @@line_left@@ @@line_right@@ @@left_color@@ @@left@@ @@right_color@@ @@right@@
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