File README changed (mode: 100644) (index 78f0d69..ceed2aa) |
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 after official release) |
|
|
6 |
|
. Language: PHP (plans to rewrite in C in the near future) |
7 |
7 |
. Database: PostgreSQL |
. Database: PostgreSQL |
8 |
8 |
|
|
9 |
9 |
|
|
|
15 |
15 |
. Very little dependencies, all packaged in main-stream distributions |
. Very little dependencies, all packaged in main-stream distributions |
16 |
16 |
. SELinux friendly |
. SELinux friendly |
17 |
17 |
. Very small (RPM is around 300KiB) |
. Very small (RPM is around 300KiB) |
|
18 |
|
. IPv6 ready |
|
19 |
|
. Internationalization ready |
18 |
20 |
|
|
19 |
21 |
|
|
20 |
22 |
== Install == |
== Install == |
|
34 |
36 |
Adjust php.ini to: |
Adjust php.ini to: |
35 |
37 |
- allow enough RAM and execution time |
- allow enough RAM and execution time |
36 |
38 |
- fix timezone |
- fix timezone |
|
39 |
|
You may want to activate an op cache to speed up the PHP scripts: |
|
40 |
|
yum install php-opcache |
|
41 |
|
Also, we recommend to activate opcache also for cli: |
|
42 |
|
change opcache.enable_cli to 1 in /etc/php.d/10-opcache.ini or |
|
43 |
|
/etc/php-zts.d/10-opcache.ini. |
37 |
44 |
|
|
38 |
45 |
. Activate web server |
. Activate web server |
39 |
46 |
# systemctl enable httpd.service |
# systemctl enable httpd.service |
|
94 |
101 |
|
|
95 |
102 |
|
|
96 |
103 |
== Thanks == |
== Thanks == |
97 |
|
. Special thanks to my family that supported me in this project. |
|
|
104 |
|
. Special thanks to my family that supports me in this project. |
98 |
105 |
. Special thanks to my brother that contributed brain and time to this project. |
. Special thanks to my brother that contributed brain and time to this project. |
99 |
106 |
. Special thanks to git people for the best tool to manage the sources. |
. Special thanks to git people for the best tool to manage the sources. |
100 |
107 |
. Special thanks to Petre Bandac for free hosting of rg2 server. |
. Special thanks to Petre Bandac for free hosting of rg2 server. |
|
102 |
109 |
. Special thanks to gitosys, Gitorious and other projects from where I learned |
. Special thanks to gitosys, Gitorious and other projects from where I learned |
103 |
110 |
things. |
things. |
104 |
111 |
. Special thanks to OWASP for their good documentation on how to write a |
. Special thanks to OWASP for their good documentation on how to write a |
105 |
|
web application. |
|
|
112 |
|
secure web application. |
106 |
113 |
. See AUTHORS file for all the people who contributed to this project. |
. See AUTHORS file for all the people who contributed to this project. |
File TODO changed (mode: 100644) (index 5ad51c5..a9d0a84) |
1 |
1 |
== Where I stopped last time == |
== Where I stopped last time == |
2 |
|
[ ] First page: our mission, how do I install it etc.? |
|
3 |
|
[ ] Seems the session expires even I make some activity. Unit test? |
|
|
2 |
|
[ ] In merge request page, must be presents also the patch, exactly like |
|
3 |
|
on 'Log' page. |
|
4 |
|
[ ] Detaliile despre merge request nu contin 'refs', cu toate ca apar in tabelul |
|
5 |
|
din pagina precedenta. |
|
6 |
|
[ ] Test push for the virtual machine and release it. |
|
7 |
|
Push by ssh is working. |
|
8 |
|
git not: Please make sure you have the correct access rights |
|
9 |
|
and the repository exists. |
|
10 |
|
It is working also for git; it is transformed into a merge request. |
|
11 |
|
[ ] I am able to disable pull requests? Anon yes, but the other ones? |
|
12 |
|
[ ] Seems the session expires even if I make some activity. Unit test? |
4 |
13 |
[ ] Check 'description_nice' and apply this everywhere. Maybe we should unset |
[ ] Check 'description_nice' and apply this everywhere. Maybe we should unset |
5 |
14 |
'description', so people will not be tempted to use it. |
'description', so people will not be tempted to use it. |
6 |
15 |
Maybe just overwrite 'description'. |
Maybe just overwrite 'description'. |
7 |
|
Planul este sa auditez peste tot dca folosesc variabile luate cu |
|
|
16 |
|
Planul este sa auditez peste tot daca folosesc variabile luate cu |
8 |
17 |
rg_var_str, rg_var_re & rg_var_cookie_re. si le trintesc pe |
rg_var_str, rg_var_re & rg_var_cookie_re. si le trintesc pe |
9 |
18 |
output fara a le trece prin template sau rg_xss_safe. |
output fara a le trece prin template sau rg_xss_safe. |
10 |
19 |
Apoi, ar trebui sa fac si nl2br pe toate textele, just in case. |
Apoi, ar trebui sa fac si nl2br pe toate textele, just in case. |
|
12 |
21 |
proiectului, e nevoie. Dar intr-un form, in textarea, nu e nevoie. |
proiectului, e nevoie. Dar intr-un form, in textarea, nu e nevoie. |
13 |
22 |
Apoi as putea elimina description_nice. |
Apoi as putea elimina description_nice. |
14 |
23 |
[ ] Security: Link-uri + xss (Ionut) |
[ ] Security: Link-uri + xss (Ionut) |
15 |
|
[ ] Only one daemon should update the structure, else they will conflict. |
|
16 |
|
[ ] Beta sign. |
|
17 |
24 |
[ ] Use a cache var to signal all daemons that we are ready to go. |
[ ] Use a cache var to signal all daemons that we are ready to go. |
18 |
25 |
Or better, a file in /var/lib/rocketgit? |
Or better, a file in /var/lib/rocketgit? |
19 |
|
[ ] Recheck what may be run as root in scripts/ folder |
|
20 |
26 |
[ ] We need to be able to delete old log files! We cannot release the vm |
[ ] We need to be able to delete old log files! We cannot release the vm |
21 |
27 |
without this! |
without this! |
22 |
28 |
[ ] Upload kvm image to downloads.rocketgit.com. Sign it? sha256 it? |
[ ] Upload kvm image to downloads.rocketgit.com. Sign it? sha256 it? |
23 |
29 |
[ ] Security: validate sparas! |
[ ] Security: validate sparas! |
24 |
30 |
[ ] Add "Spread the word!" on website. |
[ ] Add "Spread the word!" on website. |
25 |
|
[ ] Add an invite form (only for logged-in people - because of spam) that |
|
26 |
|
will send mail to a friend with all the details. |
|
27 |
31 |
[ ] Menus - change color for selected items, not the background color. |
[ ] Menus - change color for selected items, not the background color. |
|
32 |
|
[ ] Merge requests are not ok - still using files. |
|
33 |
|
[ ] Daca creez repo, nu-mi creaza dir-ul (de fapt, nu marcheaza in cache ca l-a |
|
34 |
|
creat din cauza event-ului care nu poate sa se conecteze la cache: |
|
35 |
|
broken pipe. Foarte ciudat. De ce nu ar putea trimite? |
|
36 |
|
Probabil socket-ul nu mai e deschis pentru ca cache-ul s-a restartat? |
|
37 |
|
[ ] Seems that 'token_key' is not created at boot time! Bad! |
|
38 |
|
[ ] I can do a select before write to be sure socket is open. |
|
39 |
|
If I get a error signal from select, reopen the socket. |
|
40 |
|
[ ] Implement 'clone' because is easy. The mrs will be a little bit harder. |
|
41 |
|
[ ] SPF? mail-ul ajunge in spam! |
28 |
42 |
[ ] |
[ ] |
29 |
43 |
|
|
30 |
44 |
== BEFORE NEXT RELEASE == |
== BEFORE NEXT RELEASE == |
|
45 |
|
[ ] We should clean anon namespaces if they fail? name them 'something.tmp' |
|
46 |
|
till after succesfully run receive-pack. Or just compare with |
|
47 |
|
the db? |
|
48 |
|
[ ] When a user succesfuly log in, generate a signed token to be used in case |
|
49 |
|
of brute force attack on his account. With that token he will be able |
|
50 |
|
to bypass rate limitting. |
|
51 |
|
[ ] slogan: it is not rocket science |
|
52 |
|
[ ] Only one daemon should update the structure, else they will conflict. |
|
53 |
|
Dpne. Check. |
|
54 |
|
[ ] nofollow la logout; poate si in alte pati |
|
55 |
|
[ ] Check if SSL cyphers are ok |
|
56 |
|
[ ] Se pare ca autogenerez drepturi 'All' pentru orice user asupra repo-ului. |
|
57 |
|
Se pare ca si la "Path rights"! |
|
58 |
|
Rezolvat. Ramine problema ca am drepturi full dublate. Nu stiu daca e |
|
59 |
|
ok sau nu. |
|
60 |
|
[ ] Binary files - diff? |
|
61 |
|
[ ] ionut: Nu e usor sa selectezi url-ul de clonare, tu il ai link: ex: git://git.rocketgit.com/user/catalinux/rocketgit |
|
62 |
|
Pare ca "git://" nu apare in link. |
|
63 |
|
Sugestia mea: ori faci un textarea, ori folosesti o librarie pentru |
|
64 |
|
copy/paste, vezi exemplu cum face github: |
|
65 |
|
https://github.com/blog/1365-a-more-transparent-clipboard-button sau |
|
66 |
|
http://davidwalsh.name/clipboard |
|
67 |
|
[ ] ionut: Ai sectiuni de dimensiuni fixe 700px, |
|
68 |
|
gen: http://rocketgit.com/op/features, daca vrei poti incerca sa |
|
69 |
|
folosesti css3, flex-box, ceva informatii gasesti aici: |
|
70 |
|
http://www.w3schools.com/cssref/css3_pr_flex-flow.asp |
|
71 |
|
[ ] Would be nice to give more informations when we auto generate keys |
|
72 |
|
- something like 'Autogenerated - because repo is public". |
|
73 |
|
[ ] Deal with keys with spaces. |
|
74 |
|
[ ] Add an invite form (only for logged-in people - because of spam) that |
|
75 |
|
will send mail to a friend with all the details. |
|
76 |
|
[ ] Graph with the server load. |
31 |
77 |
[ ] Warn users on the first page for behind-the-firewall installations |
[ ] Warn users on the first page for behind-the-firewall installations |
32 |
78 |
that a new version is available. Maybe also the severity level. |
that a new version is available. Maybe also the severity level. |
33 |
79 |
[ ] Add unit test for 'copy to' into git_log1. There is already one but does |
[ ] Add unit test for 'copy to' into git_log1. There is already one but does |
|
... |
... |
them after processing is done. |
714 |
760 |
Maybe, do it generic, allow a text field to enumerate what should be in a commit! |
Maybe, do it generic, allow a text field to enumerate what should be in a commit! |
715 |
761 |
Also, present a list with checkboxex: at least Signoff-by, Reported-by, Acked-by! |
Also, present a list with checkboxex: at least Signoff-by, Reported-by, Acked-by! |
716 |
762 |
[ ] Linus on why GitHub sucks: https://github.com/torvalds/linux/pull/17#issuecomment-5654674 |
[ ] Linus on why GitHub sucks: https://github.com/torvalds/linux/pull/17#issuecomment-5654674 |
|
763 |
|
- Valid name and valid e-mail address |
|
764 |
|
- Why the destination should pull? |
|
765 |
|
- A shortlog of the changes (1 line) |
|
766 |
|
- A proper diffstat |
|
767 |
|
- changelog should be shown with a monospace font? |
|
768 |
|
- First line should be <= 50 chars (short log); then an empty line |
|
769 |
|
- Rest of commit message to be wrap at 72 chars. |
|
770 |
|
- Use git-request-pull for merge requests? |
|
771 |
|
- Exemplu de pull rquest ok: https://groups.google.com/forum/#!topic/linux.kernel/w957vpu3PPU |
|
772 |
|
- |
|
773 |
|
[ ] We need to have a link to current comment/etc. |
717 |
774 |
[ ] Warn if commit messages are too long (no wrap). |
[ ] Warn if commit messages are too long (no wrap). |
718 |
775 |
[ ] Allow the possibility to send an e-mail to maintainer from web with a pull request |
[ ] Allow the possibility to send an e-mail to maintainer from web with a pull request |
719 |
|
[ ] Check https://github.com/torvalds/linux/pull/17#issuecomment-5654674 |
|
720 |
776 |
[ ] Merge requests e-mail: explanation of why to pull, diffstat! Maybe also the |
[ ] Merge requests e-mail: explanation of why to pull, diffstat! Maybe also the |
721 |
777 |
patch if is small. |
patch if is small. |
722 |
778 |
[ ] Check git-request-pull |
[ ] Check git-request-pull |
File inc/admin.inc.php changed (mode: 100644) (index 2a818a7..160cb41) |
... |
... |
function rg_init($db, $rg) |
230 |
230 |
return $ret; |
return $ret; |
231 |
231 |
} |
} |
232 |
232 |
|
|
|
233 |
|
/* |
|
234 |
|
* Send some daily statistics to the admin |
|
235 |
|
*/ |
|
236 |
|
function rg_admin_report1($db, $rg) |
|
237 |
|
{ |
|
238 |
|
global $rg_admin_email; |
|
239 |
|
|
|
240 |
|
$body = ''; |
|
241 |
|
|
|
242 |
|
$y_start = gmmktime(0, 0, 0, gmdate("m"), gmdate("d") - 1); |
|
243 |
|
$y_end = gmmktime(0, 0, 0, gmdate("m"), gmdate("d")) - 1; |
|
244 |
|
|
|
245 |
|
$body .= "Report between " . gmdate('Y-m-d H:i:s', $y_start) |
|
246 |
|
. " and " . gmdate('Y-m-d H:i:s', $y_end) . " UTC\n"; |
|
247 |
|
|
|
248 |
|
$sql = "SELECT COUNT(*) AS total FROM users"; |
|
249 |
|
$res = rg_sql_query($db, $sql); |
|
250 |
|
if ($res === FALSE) { |
|
251 |
|
$total_users = "ERR"; |
|
252 |
|
} else { |
|
253 |
|
$row = rg_sql_fetch_array($res); |
|
254 |
|
$total_users = $row['total']; |
|
255 |
|
$body .= "\nTotal users: " . $total_users . "\n"; |
|
256 |
|
} |
|
257 |
|
rg_sql_free_result($res); |
|
258 |
|
|
|
259 |
|
$sql = "SELECT COUNT(*) AS total FROM repos"; |
|
260 |
|
$res = rg_sql_query($db, $sql); |
|
261 |
|
if ($res === FALSE) { |
|
262 |
|
$total_repos = "ERR"; |
|
263 |
|
} else { |
|
264 |
|
$row = rg_sql_fetch_array($res); |
|
265 |
|
$total_repos = $row['total']; |
|
266 |
|
$body .= "\nTotal repositories: " . $total_users . "\n"; |
|
267 |
|
} |
|
268 |
|
rg_sql_free_result($res); |
|
269 |
|
|
|
270 |
|
$sql = "SELECT username, realname FROM users" |
|
271 |
|
. " WHERE itime >= $y_start" |
|
272 |
|
. " AND itime <= $y_end"; |
|
273 |
|
$res = rg_sql_query($db, $sql); |
|
274 |
|
if ($res === FALSE) { |
|
275 |
|
$users = "ERR"; |
|
276 |
|
} else { |
|
277 |
|
$users = 0; |
|
278 |
|
$list = ''; |
|
279 |
|
while (($row = rg_sql_fetch_array($res))) { |
|
280 |
|
$users++; |
|
281 |
|
$list .= sprintf("%30s %s\n", |
|
282 |
|
$row['username'], $row['realname']); |
|
283 |
|
} |
|
284 |
|
if ($users) |
|
285 |
|
$body .= "\nYesterday users (" . $users . "):\n" . $list; |
|
286 |
|
} |
|
287 |
|
rg_sql_free_result($res); |
|
288 |
|
|
|
289 |
|
$sql = "SELECT name, description FROM repos" |
|
290 |
|
. " WHERE itime >= $y_start" |
|
291 |
|
. " AND itime <= $y_end"; |
|
292 |
|
$res = rg_sql_query($db, $sql); |
|
293 |
|
if ($res === FALSE) { |
|
294 |
|
$repos = "ERR"; |
|
295 |
|
} else { |
|
296 |
|
$repos = 0; |
|
297 |
|
$list = ''; |
|
298 |
|
while (($row = rg_sql_fetch_array($res))) { |
|
299 |
|
$repos++; |
|
300 |
|
$desc = substr($row['description'], 0, 50); |
|
301 |
|
$desc = preg_replace('/\s/', ' ', $desc); |
|
302 |
|
$list .= $row['name'] . " - " . $desc . "\n"; |
|
303 |
|
} |
|
304 |
|
if ($repos) |
|
305 |
|
$body .= "\nYesterday repos (" . $repos . "):\n" . $list; |
|
306 |
|
} |
|
307 |
|
rg_sql_free_result($res); |
|
308 |
|
|
|
309 |
|
$rg['ui::email'] = $rg_admin_email; |
|
310 |
|
$rg['mail::subject'] = 'RocketGit daily report' |
|
311 |
|
. ' [' . $users . '/' . $total_users . ']' |
|
312 |
|
. ' [' . $repos . '/' . $total_repos . ']'; |
|
313 |
|
$rg['mail::body'] = $body; |
|
314 |
|
rg_mail_template("mail/admin/report1", $rg); |
|
315 |
|
} |
|
316 |
|
|
233 |
317 |
?> |
?> |
File inc/cache.inc.php changed (mode: 100644) (index 64df4a3..7ef4077) |
... |
... |
function rg_cache_get($ns_var) |
304 |
304 |
|
|
305 |
305 |
$c = rg_socket($rg_cache_socket, |
$c = rg_socket($rg_cache_socket, |
306 |
306 |
"GET " . $ns_var . "\n", $rg_cache_timeout, 1); |
"GET " . $ns_var . "\n", $rg_cache_timeout, 1); |
307 |
|
if ($c === FALSE) { |
|
308 |
|
// Give up for the rest of the session |
|
309 |
|
$rg_cache_enable = FALSE; |
|
|
307 |
|
if ($c === FALSE) |
310 |
308 |
break; |
break; |
311 |
|
} |
|
312 |
309 |
|
|
313 |
310 |
$t = explode(" ", $c, 2); |
$t = explode(" ", $c, 2); |
314 |
311 |
if (strcmp($t[0], "OK") != 0) |
if (strcmp($t[0], "OK") != 0) |
|
... |
... |
function rg_cache_set($ns_var, $value) |
368 |
365 |
break; |
break; |
369 |
366 |
|
|
370 |
367 |
$c = rg_socket($rg_cache_socket, "SET " . $ns_var . "=" |
$c = rg_socket($rg_cache_socket, "SET " . $ns_var . "=" |
371 |
|
. rg_cache_prepare($value) . "\n", $rg_cache_timeout, 1); |
|
372 |
|
if ($c === FALSE) { |
|
373 |
|
// Give up for the rest of the session |
|
374 |
|
if ($rg_cache_debug) |
|
375 |
|
rg_log("Disable cache because of errors"); |
|
376 |
|
$rg_cache_enable = FALSE; |
|
|
368 |
|
. rg_cache_prepare($value) . "\n", $rg_cache_timeout, 3); |
|
369 |
|
if ($c === FALSE) |
377 |
370 |
break; |
break; |
378 |
|
} |
|
379 |
371 |
|
|
380 |
372 |
if (strncmp($c, "OK", 2) != 0) |
if (strncmp($c, "OK", 2) != 0) |
381 |
373 |
break; |
break; |
|
... |
... |
function rg_cache_inc($ns_var) |
413 |
405 |
|
|
414 |
406 |
$c = rg_socket($rg_cache_socket, |
$c = rg_socket($rg_cache_socket, |
415 |
407 |
"INC " . $ns_var . "\n", $rg_cache_timeout, 1); |
"INC " . $ns_var . "\n", $rg_cache_timeout, 1); |
416 |
|
if ($c === FALSE) { |
|
417 |
|
// Give up for the rest of the session |
|
418 |
|
if ($rg_cache_debug) |
|
419 |
|
rg_log("Disable cache because of errors"); |
|
420 |
|
$rg_cache_enable = FALSE; |
|
|
408 |
|
if ($c === FALSE) |
421 |
409 |
break; |
break; |
422 |
|
} |
|
423 |
410 |
|
|
424 |
411 |
if (strncmp($c, "OK", 2) != 0) |
if (strncmp($c, "OK", 2) != 0) |
425 |
412 |
break; |
break; |
|
... |
... |
function rg_cache_unset($ns_var) |
462 |
449 |
|
|
463 |
450 |
$ret = rg_socket($rg_cache_socket, |
$ret = rg_socket($rg_cache_socket, |
464 |
451 |
"UNSET " . $ns_var . "\n", $rg_cache_timeout, 1); |
"UNSET " . $ns_var . "\n", $rg_cache_timeout, 1); |
465 |
|
if ($ret === FALSE) { |
|
466 |
|
// Give up for the rest of the session |
|
467 |
|
if ($rg_cache_debug) |
|
468 |
|
rg_log("Disable cache because of errors"); |
|
469 |
|
$rg_cache_enable = FALSE; |
|
|
452 |
|
if ($ret === FALSE) |
470 |
453 |
break; |
break; |
471 |
|
} |
|
472 |
454 |
|
|
473 |
455 |
if (strncmp($ret, "NOT_FOUND", 9) == 0) |
if (strncmp($ret, "NOT_FOUND", 9) == 0) |
474 |
456 |
break; |
break; |
|
... |
... |
function rg_cache_merge($ns_var, $list) |
514 |
496 |
|
|
515 |
497 |
$c = rg_socket($rg_cache_socket, "MERGE " . $ns_var . "=" |
$c = rg_socket($rg_cache_socket, "MERGE " . $ns_var . "=" |
516 |
498 |
. rg_cache_prepare($list) . "\n", $rg_cache_timeout, 1); |
. rg_cache_prepare($list) . "\n", $rg_cache_timeout, 1); |
517 |
|
if ($c === FALSE) { |
|
518 |
|
// Give up for the rest of the session |
|
519 |
|
if ($rg_cache_debug) |
|
520 |
|
rg_log("Disable cache because of errors"); |
|
521 |
|
$rg_cache_enable = FALSE; |
|
|
499 |
|
if ($c === FALSE) |
522 |
500 |
break; |
break; |
523 |
|
} |
|
524 |
501 |
|
|
525 |
502 |
if (strncmp($c, "OK", 2) != 0) |
if (strncmp($c, "OK", 2) != 0) |
526 |
503 |
break; |
break; |
File inc/repo.inc.php changed (mode: 100644) (index f2de19b..8781f22) |
... |
... |
function rg_repo_rights_inject($db, $obj_id, $type, $owner, $uid) |
82 |
82 |
break; |
break; |
83 |
83 |
|
|
84 |
84 |
if ($ui['is_admin'] == 1) { |
if ($ui['is_admin'] == 1) { |
|
85 |
|
$a['uid'] = $owner; |
85 |
86 |
$a['rights'] = rg_rights_all($type); |
$a['rights'] = rg_rights_all($type); |
|
87 |
|
$a['description'] = 'Autogenerated (you are admin)'; |
86 |
88 |
$ret[] = $a; |
$ret[] = $a; |
87 |
89 |
} |
} |
88 |
90 |
} |
} |
|
... |
... |
function rg_repo_rights_inject($db, $obj_id, $type, $owner, $uid) |
95 |
97 |
|
|
96 |
98 |
// Here, rights to inject, even if repo is not public |
// Here, rights to inject, even if repo is not public |
97 |
99 |
if (strcmp($type, "repo_path") == 0) { |
if (strcmp($type, "repo_path") == 0) { |
|
100 |
|
$a['uid'] = 0; |
98 |
101 |
$a['prio'] = 30001; |
$a['prio'] = 30001; |
99 |
102 |
$a['rights'] = "PW"; // push + whitespace |
$a['rights'] = "PW"; // push + whitespace |
|
103 |
|
$a['description'] = 'Autogenerated (sane default)'; |
100 |
104 |
$ret[] = $a; |
$ret[] = $a; |
101 |
105 |
} |
} |
102 |
106 |
|
|
|
... |
... |
function rg_repo_rights_inject($db, $obj_id, $type, $owner, $uid) |
105 |
109 |
break; |
break; |
106 |
110 |
|
|
107 |
111 |
if (strcmp($type, "repo") == 0) { |
if (strcmp($type, "repo") == 0) { |
|
112 |
|
$a['uid'] = 0; |
108 |
113 |
$a['rights'] = "AaB"; // access repo + access bug tracker + add bugs |
$a['rights'] = "AaB"; // access repo + access bug tracker + add bugs |
|
114 |
|
$a['description'] = 'Autogenerated (repo is public)'; |
109 |
115 |
$ret[] = $a; |
$ret[] = $a; |
110 |
116 |
} else if (strcmp($type, "repo_refs") == 0) { |
} else if (strcmp($type, "repo_refs") == 0) { |
|
117 |
|
$a['uid'] = 0; |
111 |
118 |
$a['rights'] = "F"; // Fetch |
$a['rights'] = "F"; // Fetch |
|
119 |
|
$a['description'] = 'Autogenerated (repo is public)'; |
112 |
120 |
$ret[] = $a; |
$ret[] = $a; |
113 |
121 |
} else if (strcmp($type, "repo_path") == 0) { |
} else if (strcmp($type, "repo_path") == 0) { |
114 |
122 |
} else { |
} else { |
|
... |
... |
function rg_repo_git_done($db, $repo_id) |
1172 |
1180 |
while (1) { |
while (1) { |
1173 |
1181 |
$params = array("repo_id" => $repo_id); |
$params = array("repo_id" => $repo_id); |
1174 |
1182 |
|
|
1175 |
|
rg_cache_merge('repo_by_id::' . $repo_id, $params); |
|
|
1183 |
|
rg_cache_merge('repo_by_id::' . $repo_id, |
|
1184 |
|
array('git_dir_done' => 1)); |
1176 |
1185 |
|
|
1177 |
1186 |
$sql = "UPDATE repos SET git_dir_done = 1" |
$sql = "UPDATE repos SET git_dir_done = 1" |
1178 |
1187 |
. " WHERE repo_id = @@repo_id@@"; |
. " WHERE repo_id = @@repo_id@@"; |
File inc/ssh.inc.php changed (mode: 100644) (index 28b8c81..16ee8c1) |
... |
... |
function rg_ssh_repos($db, $uid) |
25 |
25 |
{ |
{ |
26 |
26 |
rg_log("ssh_repos"); |
rg_log("ssh_repos"); |
27 |
27 |
|
|
28 |
|
echo "Repositories (name, creation, disk used):\n"; |
|
29 |
28 |
$sql = "SELECT * FROM repos" |
$sql = "SELECT * FROM repos" |
30 |
29 |
. " WHERE uid = $uid" |
. " WHERE uid = $uid" |
31 |
30 |
. " AND deleted = 0" |
. " AND deleted = 0" |
32 |
31 |
. " ORDER BY name, itime"; |
. " ORDER BY name, itime"; |
33 |
32 |
$pad = " "; |
$pad = " "; |
34 |
33 |
$res = rg_sql_query($db, $sql); |
$res = rg_sql_query($db, $sql); |
35 |
|
while (($row = rg_sql_fetch_array($res))) { |
|
36 |
|
echo substr(substr($row['name'], 0, 40) . $pad, 0, 32) |
|
37 |
|
. " " . gmdate("Y-m-d", $row['itime']) |
|
38 |
|
. " " . rg_1024($row['disk_used_mb']) |
|
39 |
|
. "\n"; |
|
|
34 |
|
$rows = rg_sql_num_rows($res); |
|
35 |
|
if ($rows > 0) { |
|
36 |
|
echo "Repositories (name, creation, disk used):\n"; |
|
37 |
|
while (($row = rg_sql_fetch_array($res))) { |
|
38 |
|
echo substr(substr($row['name'], 0, 40) . $pad, 0, 32) |
|
39 |
|
. " " . gmdate("Y-m-d", $row['itime']) |
|
40 |
|
. " " . rg_1024($row['disk_used_mb']) |
|
41 |
|
. "\n"; |
|
42 |
|
} |
|
43 |
|
} else { |
|
44 |
|
echo "You have no repository.\n"; |
40 |
45 |
} |
} |
41 |
46 |
rg_sql_free_result($res); |
rg_sql_free_result($res); |
42 |
47 |
|
|
|
... |
... |
function rg_ssh_repo($db, $uid, $paras) |
58 |
63 |
$repo_name = trim($paras[0]); |
$repo_name = trim($paras[0]); |
59 |
64 |
|
|
60 |
65 |
$ri = rg_repo_info($db, 0, $uid, $repo_name); |
$ri = rg_repo_info($db, 0, $uid, $repo_name); |
61 |
|
if ($ri === FALSE) { |
|
|
66 |
|
if ($ri['exists'] != 1) { |
62 |
67 |
echo "Error: unknown repo.\n"; |
echo "Error: unknown repo.\n"; |
63 |
68 |
exit(0); |
exit(0); |
64 |
69 |
} |
} |
File inc/struct.inc.php changed (mode: 100644) (index cf12bd0..8a5ab38) |
... |
... |
function rg_sql_struct_slaves_update($db) |
617 |
617 |
|
|
618 |
618 |
$last_ts = rg_state_get($db, "slaves_create_last_ts"); |
$last_ts = rg_state_get($db, "slaves_create_last_ts"); |
619 |
619 |
if ($last_ts === FALSE) |
if ($last_ts === FALSE) |
620 |
|
break; |
|
|
620 |
|
$last_ts = 0; |
621 |
621 |
|
|
622 |
|
$last_ts = intval($last_ts); |
|
|
622 |
|
$last_ts = sprintf("%u", $last_ts); |
623 |
623 |
if ($last_ts == 0) |
if ($last_ts == 0) |
624 |
624 |
$last_ts = gmmktime(0, 0, 0, gmdate("m") - 1, 1, gmdate("Y")); |
$last_ts = gmmktime(0, 0, 0, gmdate("m") - 1, 1, gmdate("Y")); |
625 |
625 |
rg_log("last_ts=$last_ts (" . gmdate("Y-m-d", $last_ts) . ")"); |
rg_log("last_ts=$last_ts (" . gmdate("Y-m-d", $last_ts) . ")"); |
|
... |
... |
function rg_sql_struct_slaves_update($db) |
650 |
650 |
|
|
651 |
651 |
foreach ($rg_sql_struct_slaves as $table) { |
foreach ($rg_sql_struct_slaves as $table) { |
652 |
652 |
$slave_table = $table . "_" . gmdate("Y_m", $ts); |
$slave_table = $table . "_" . gmdate("Y_m", $ts); |
|
653 |
|
|
|
654 |
|
// First, check if exists. It is possible that |
|
655 |
|
// we did the update but we could not set the cache. |
|
656 |
|
$sql = "SELECT 1 FROM pg_class" |
|
657 |
|
. " WHERE relname = '" . $slave_table . "'"; |
|
658 |
|
$res = rg_sql_query($db, $sql); |
|
659 |
|
if ($res === FALSE) { |
|
660 |
|
$ok = FALSE; |
|
661 |
|
break; |
|
662 |
|
} |
|
663 |
|
$rows = rg_sql_num_rows($res); |
|
664 |
|
rg_sql_free_result($res); |
|
665 |
|
if ($rows > 0) |
|
666 |
|
continue; |
|
667 |
|
|
653 |
668 |
$sql = "CREATE TABLE " . $slave_table |
$sql = "CREATE TABLE " . $slave_table |
654 |
669 |
. " (CHECK(itime >= $ts AND itime <= " . ($next_ts - 1) . "))" |
. " (CHECK(itime >= $ts AND itime <= " . ($next_ts - 1) . "))" |
655 |
670 |
. " INHERITS (" . $table . ")"; |
. " INHERITS (" . $table . ")"; |
|
... |
... |
function rg_sql_struct_slaves_update($db) |
675 |
690 |
if ($ok === FALSE) |
if ($ok === FALSE) |
676 |
691 |
break; |
break; |
677 |
692 |
|
|
|
693 |
|
if (rg_sql_commit($db) !== TRUE) |
|
694 |
|
break; |
|
695 |
|
|
678 |
696 |
$r = rg_state_set($db, "slaves_create_last_ts", $stop_ts); |
$r = rg_state_set($db, "slaves_create_last_ts", $stop_ts); |
679 |
697 |
if ($r !== TRUE) { |
if ($r !== TRUE) { |
680 |
698 |
rg_log("Cannot create slave (" . rg_state_error() . ")"); |
rg_log("Cannot create slave (" . rg_state_error() . ")"); |
681 |
699 |
break; |
break; |
682 |
700 |
} |
} |
683 |
701 |
|
|
684 |
|
if (rg_sql_commit($db) !== TRUE) |
|
685 |
|
break; |
|
686 |
|
|
|
687 |
702 |
$rollback = 0; |
$rollback = 0; |
688 |
703 |
$ret = TRUE; |
$ret = TRUE; |
689 |
704 |
break; |
break; |
File samples/rg.conf changed (mode: 100644) (index fb8da8e..f49be15) |
1 |
1 |
# This is the apache configuration file for RocketGit |
# This is the apache configuration file for RocketGit |
2 |
2 |
|
|
|
3 |
|
<Directory "/usr/share/rocketgit/root"> |
|
4 |
|
AllowOverride All |
|
5 |
|
Order allow,deny |
|
6 |
|
Allow from all |
|
7 |
|
Require all granted |
|
8 |
|
|
|
9 |
|
# Cache at will |
|
10 |
|
<FilesMatch "(?i)^.*\.(ico|flv|jpg|jpeg|png|gif|js|css|swf)$"> |
|
11 |
|
FileETag MTime Size |
|
12 |
|
</FilesMatch> |
|
13 |
|
|
|
14 |
|
<IfModule mod_expires.c> |
|
15 |
|
ExpiresActive On |
|
16 |
|
ExpiresByType image/vnd.microsoft.icon "access plus 7 days" |
|
17 |
|
ExpiresByType image/png "access plus 1 day" |
|
18 |
|
ExpiresByType text/css "access plus 1 day" |
|
19 |
|
ExpiresByType text/javascript "access plus 1 day" |
|
20 |
|
ExpiresByType application/javascript "access plus 1 day" |
|
21 |
|
ExpiresByType application/x-javascript "access plus 1 day" |
|
22 |
|
</IfModule> |
|
23 |
|
</Directory> |
|
24 |
|
|
3 |
25 |
<VirtualHost *:80> |
<VirtualHost *:80> |
4 |
26 |
ServerName rg.domain.tld |
ServerName rg.domain.tld |
5 |
27 |
ServerAlias rg |
ServerAlias rg |
6 |
28 |
DocumentRoot /usr/share/rocketgit/root/ |
DocumentRoot /usr/share/rocketgit/root/ |
7 |
29 |
ErrorLog logs/rocketgit-error_log |
ErrorLog logs/rocketgit-error_log |
8 |
30 |
CustomLog logs/rocketgit-access_log common |
CustomLog logs/rocketgit-access_log common |
9 |
|
<Directory "/usr/share/rocketgit/root"> |
|
10 |
|
AllowOverride All |
|
11 |
|
Order allow,deny |
|
12 |
|
Allow from all |
|
13 |
|
Require all granted |
|
14 |
|
</Directory> |
|
15 |
31 |
|
|
16 |
32 |
KeepAlive On |
KeepAlive On |
17 |
33 |
MaxKeepAliveRequests 1000 |
MaxKeepAliveRequests 1000 |
|
34 |
50 |
<IfModule mod_headers.c> |
<IfModule mod_headers.c> |
35 |
51 |
Header always append X-Frame-Options DENY |
Header always append X-Frame-Options DENY |
36 |
52 |
# Add this for SSL |
# Add this for SSL |
37 |
|
#Header set Strict-Transport-Security "max-age=31536000" |
|
|
53 |
|
Header set Strict-Transport-Security "max-age=31536000" |
38 |
54 |
</IfModule> |
</IfModule> |
39 |
55 |
|
|
40 |
56 |
# Compress |
# Compress |
41 |
57 |
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/x-javascript |
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/x-javascript |
42 |
58 |
DeflateBufferSize 81920 |
DeflateBufferSize 81920 |
|
59 |
|
</VirtualHost> |
43 |
60 |
|
|
44 |
|
# Cache at will |
|
45 |
|
<FilesMatch "(?i)^.*\.(ico|flv|jpg|jpeg|png|gif|js|css|swf)$"> |
|
46 |
|
FileETag MTime Size |
|
47 |
|
</FilesMatch> |
|
|
61 |
|
<VirtualHost *:443> |
|
62 |
|
DocumentRoot /usr/share/rocketgit/root/ |
48 |
63 |
|
|
49 |
|
<IfModule mod_expires.c> |
|
50 |
|
ExpiresActive On |
|
51 |
|
ExpiresByType image/vnd.microsoft.icon "access plus 7 days" |
|
52 |
|
ExpiresByType image/png "access plus 1 day" |
|
53 |
|
ExpiresByType text/css "access plus 1 day" |
|
54 |
|
ExpiresByType text/javascript "access plus 1 day" |
|
55 |
|
ExpiresByType application/javascript "access plus 1 day" |
|
56 |
|
ExpiresByType application/x-javascript "access plus 1 day" |
|
57 |
|
</IfModule> |
|
|
64 |
|
ErrorLog logs/rocketgit-ssl_error_log |
|
65 |
|
CustomLog logs/ssl_request_log \ |
|
66 |
|
"%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b" |
|
67 |
|
TransferLog logs/rocketgit-ssl_access_log |
|
68 |
|
|
|
69 |
|
KeepAlive On |
|
70 |
|
MaxKeepAliveRequests 1000 |
|
71 |
|
KeepAliveTimeout 10 |
|
72 |
|
|
|
73 |
|
RewriteEngine On |
|
74 |
|
#RewriteLog /var/log/httpd/rg-Rewrite.log |
|
75 |
|
#RewriteLogLevel 3 |
|
76 |
|
|
|
77 |
|
# Allow .ico, 'themes' folder and robots.txt |
|
78 |
|
# Also, avoid scripts that are looking for exploits |
|
79 |
|
RewriteCond %{REQUEST_URI} ^/(favicon\.ico|themes/.*|robots\.txt|.*\.php.*|.*\.html)$ |
|
80 |
|
RewriteRule .* - [last] |
|
81 |
|
|
|
82 |
|
# all rest |
|
83 |
|
RewriteRule (.*) /index.php?rwe=1&vv=$1 [last,qsappend] |
|
84 |
|
|
|
85 |
|
LogLevel warn |
|
86 |
|
SSLEngine on |
|
87 |
|
SSLProtocol all -SSLv2 |
|
88 |
|
SSLCipherSuite PROFILE=SYSTEM |
|
89 |
|
|
|
90 |
|
SSLCertificateFile /etc/pki/tls/certs/localhost.crt |
|
91 |
|
SSLCertificateKeyFile /etc/pki/tls/private/localhost.key |
|
92 |
|
|
|
93 |
|
<Files ~ "\.(cgi|shtml|phtml|php3?)$"> |
|
94 |
|
SSLOptions +StdEnvVars |
|
95 |
|
</Files> |
|
96 |
|
|
|
97 |
|
# Compress - check if is ok from security pov |
|
98 |
|
#AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/x-javascript |
|
99 |
|
#DeflateBufferSize 81920 |
58 |
100 |
</VirtualHost> |
</VirtualHost> |
File scripts/cron.php changed (mode: 100644) (index e0d2586..783b378) |
... |
... |
require_once($INC . "/struct.inc.php"); |
15 |
15 |
require_once($INC . "/repo.inc.php"); |
require_once($INC . "/repo.inc.php"); |
16 |
16 |
require_once($INC . "/keys.inc.php"); |
require_once($INC . "/keys.inc.php"); |
17 |
17 |
require_once($INC . "/fixes.inc.php"); |
require_once($INC . "/fixes.inc.php"); |
|
18 |
|
require_once($INC . "/mr.inc.php"); |
|
19 |
|
require_once($INC . "/admin.inc.php"); |
18 |
20 |
require_once($INC . "/ver.php"); |
require_once($INC . "/ver.php"); |
19 |
21 |
|
|
20 |
22 |
rg_log_set_file($rg_log_dir . "/cron.log"); |
rg_log_set_file($rg_log_dir . "/cron.log"); |
21 |
23 |
rg_log_set_sid("000000"); // to spread the logs |
rg_log_set_sid("000000"); // to spread the logs |
22 |
24 |
|
|
|
25 |
|
if (rg_load() > 5) |
|
26 |
|
exit(0); |
|
27 |
|
|
23 |
28 |
// locking |
// locking |
24 |
29 |
rg_lock_or_exit("cron.lock"); |
rg_lock_or_exit("cron.lock"); |
25 |
30 |
|
|
|
... |
... |
$first_install = rg_state_get($db, 'first_install'); |
49 |
54 |
if ($first_install === '') |
if ($first_install === '') |
50 |
55 |
exit(0); |
exit(0); |
51 |
56 |
|
|
52 |
|
if ((gmdate("H") == 0) && (gmdate("i") == 3)) { |
|
|
57 |
|
if (gmdate("Hi") == "0105") { |
53 |
58 |
while (1) { |
while (1) { |
54 |
59 |
rg_log("Compute repository sizes if dirty..."); |
rg_log("Compute repository sizes if dirty..."); |
55 |
60 |
// delete 'dirty' files |
// delete 'dirty' files |
|
... |
... |
if ((gmdate("H") == 0) && (gmdate("i") == 3)) { |
67 |
72 |
|
|
68 |
73 |
$all_files = $row['master'] == 0 ? TRUE : FALSE; |
$all_files = $row['master'] == 0 ? TRUE : FALSE; |
69 |
74 |
$disk_used = rg_repo_size($repo_path, $all_files); |
$disk_used = rg_repo_size($repo_path, $all_files); |
70 |
|
if ($disk_used_mb === FALSE) { |
|
|
75 |
|
if ($disk_used === FALSE) { |
71 |
76 |
rg_log("Cannot compute the repo size: " . rg_repo_error()); |
rg_log("Cannot compute the repo size: " . rg_repo_error()); |
72 |
77 |
continue; |
continue; |
73 |
78 |
} |
} |
|
... |
... |
if ((gmdate("H") == 0) && (gmdate("i") == 3)) { |
111 |
116 |
} |
} |
112 |
117 |
} |
} |
113 |
118 |
|
|
114 |
|
if (gmdate("H") == 3) { |
|
|
119 |
|
if (gmdate("Hi") == "0300") { |
115 |
120 |
rg_log("Clean old forget_pass entries..."); |
rg_log("Clean old forget_pass entries..."); |
116 |
121 |
$sql = "DELETE FROM forgot_pass WHERE expire < $now"; |
$sql = "DELETE FROM forgot_pass WHERE expire < $now"; |
117 |
122 |
$res = rg_sql_query($db, $sql); |
$res = rg_sql_query($db, $sql); |
118 |
123 |
rg_sql_free_result($res); |
rg_sql_free_result($res); |
119 |
124 |
} |
} |
120 |
125 |
|
|
121 |
|
if (gmdate("H") == 1) { |
|
|
126 |
|
if (gmdate("i") == "30") { |
122 |
127 |
rg_log("Clean old tokens..."); |
rg_log("Clean old tokens..."); |
123 |
128 |
$sql = "DELETE FROM tokens WHERE expire < $now"; |
$sql = "DELETE FROM tokens WHERE expire < $now"; |
124 |
129 |
$res = rg_sql_query($db, $sql); |
$res = rg_sql_query($db, $sql); |
125 |
130 |
rg_sql_free_result($res); |
rg_sql_free_result($res); |
126 |
131 |
} |
} |
127 |
132 |
|
|
128 |
|
if (gmdate("H") == 1) { |
|
|
133 |
|
if (gmdate("i") == "01") { |
129 |
134 |
rg_log("Clean old sess entries..."); |
rg_log("Clean old sess entries..."); |
130 |
135 |
$sql = "DELETE FROM sess WHERE expire < $now"; |
$sql = "DELETE FROM sess WHERE expire < $now"; |
131 |
136 |
$res = rg_sql_query($db, $sql); |
$res = rg_sql_query($db, $sql); |
|
... |
... |
if (gmdate("H") == 1) { |
134 |
139 |
|
|
135 |
140 |
rg_log_cron(); |
rg_log_cron(); |
136 |
141 |
|
|
137 |
|
if (gmdate("H") == 4) |
|
138 |
|
rg_sql_struct_slaves_update($db); |
|
|
142 |
|
rg_sql_struct_slaves_update($db); |
|
143 |
|
|
|
144 |
|
if (gmdate("Hi") == "0100") |
|
145 |
|
rg_admin_report1($db, $rg); |
139 |
146 |
|
|
|
147 |
|
// TODO: move it as an event after the push |
|
148 |
|
rg_mr_queue_process($db); |
140 |
149 |
|
|
141 |
150 |
rg_log("Done!"); |
rg_log("Done!"); |
142 |
151 |
?> |
?> |
File scripts/q.php deleted (index 7fb1895..0000000) |
1 |
|
<?php |
|
2 |
|
// This is called by cron, and is persistent. |
|
3 |
|
// It takes care of repository init/clone, merge request to db etc. |
|
4 |
|
error_reporting(E_ALL); |
|
5 |
|
ini_set("track_errors", "On"); |
|
6 |
|
|
|
7 |
|
$now = time(); |
|
8 |
|
$_s = microtime(TRUE); |
|
9 |
|
|
|
10 |
|
require_once("/etc/rocketgit/config.php"); |
|
11 |
|
|
|
12 |
|
$INC = dirname(__FILE__) . "/../inc"; |
|
13 |
|
require_once($INC . "/init.inc.php"); |
|
14 |
|
require_once($INC . "/log.inc.php"); |
|
15 |
|
require_once($INC . "/sql.inc.php"); |
|
16 |
|
require_once($INC . "/struct.inc.php"); |
|
17 |
|
require_once($INC . "/repo.inc.php"); |
|
18 |
|
require_once($INC . "/prof.inc.php"); |
|
19 |
|
require_once($INC . "/mr.inc.php"); |
|
20 |
|
require_once($INC . "/fixes.inc.php"); |
|
21 |
|
require_once($INC . "/plan.inc.php"); |
|
22 |
|
require_once($INC . "/ver.php"); |
|
23 |
|
|
|
24 |
|
rg_prof_start("MAIN"); |
|
25 |
|
|
|
26 |
|
rg_log_set_file($rg_log_dir . "/q.log"); |
|
27 |
|
rg_log_set_sid("000000"); // to spread the logs |
|
28 |
|
|
|
29 |
|
// locking |
|
30 |
|
rg_lock_or_exit("q.lock"); |
|
31 |
|
|
|
32 |
|
rg_log("Start (ver=$rocketgit_version)..."); |
|
33 |
|
|
|
34 |
|
rg_sql_app("rg-q"); |
|
35 |
|
$db = rg_sql_open($rg_sql); |
|
36 |
|
if ($db === FALSE) { |
|
37 |
|
rg_log("Cannot connect to database!"); |
|
38 |
|
// TODO: inform admin - already by e-mail? |
|
39 |
|
exit(1); |
|
40 |
|
} |
|
41 |
|
|
|
42 |
|
$r = rg_sql_struct_update($db, 0); |
|
43 |
|
if ($r !== TRUE) |
|
44 |
|
exit(1); |
|
45 |
|
|
|
46 |
|
$r = rg_fixes_update($db); |
|
47 |
|
if ($r !== TRUE) |
|
48 |
|
exit(1); |
|
49 |
|
|
|
50 |
|
$original_mtime = filemtime(__FILE__); |
|
51 |
|
|
|
52 |
|
// Check our mtime so we can upgrade the software and this script will restart. |
|
53 |
|
while (TRUE) { |
|
54 |
|
clearstatcache(); |
|
55 |
|
$mtime = filemtime(__FILE__); |
|
56 |
|
//rg_log("mtime=$mtime, original_mtime=$original_mtime"); |
|
57 |
|
if ($mtime != $original_mtime) { |
|
58 |
|
rg_log("File changed. Exiting..."); |
|
59 |
|
break; |
|
60 |
|
} |
|
61 |
|
|
|
62 |
|
// check machine load - if too big we will delay |
|
63 |
|
$load = rg_load(); |
|
64 |
|
if ($load > 10) { |
|
65 |
|
rg_log("\tLoad too big!"); |
|
66 |
|
sleep(10); |
|
67 |
|
continue; |
|
68 |
|
} |
|
69 |
|
|
|
70 |
|
// TODO: move it as an event and remove this script |
|
71 |
|
rg_mr_queue_process($db); |
|
72 |
|
|
|
73 |
|
sleep(1); |
|
74 |
|
} |
|
75 |
|
|
|
76 |
|
rg_prof_end("MAIN"); |
|
77 |
|
rg_prof_log(); |
|
78 |
|
?> |
|