added a primitive LOC graph for a directory

This commit is contained in:
hyung-hwan 2015-03-30 14:24:56 +00:00
parent 1c7909a453
commit aa1d4587cc
18 changed files with 355 additions and 42 deletions

View File

@ -789,6 +789,8 @@ class Code extends Controller
while (!feof($cloc))
{
$line = @fgets ($cloc);
if ($line === FALSE) break;
if ($line_count == 2)
{
$counter = explode (':', $line);

View File

@ -70,7 +70,7 @@ class Graph extends Controller
}
}
function history_json ($projectid = '', $path = '', $rev = SVN_REVISION_HEAD)
function history_json ($projectid = '', $path = '')
{
$this->load->model ('ProjectModel', 'projects');
@ -113,7 +113,7 @@ class Graph extends Controller
print codepot_json_encode ($history);
}
function total_loc_json ($projectid)
function folder_loc_json ($projectid = '', $path = '', $rev = SVN_REVISION_HEAD)
{
$this->load->model ('ProjectModel', 'projects');
@ -131,7 +131,13 @@ class Graph extends Controller
return;
}
// check out the whole project
// run clock.pl againt it.
$this->load->model ('SubversionModel', 'subversion');
$path = $this->converter->HexToAscii ($path);
if ($path == '.') $path = ''; /* treat a period specially */
$path = $this->_normalize_path ($path);
$cloc = $this->subversion->clocRev ($projectid, $path, $rev);
print codepot_json_encode ($cloc);
}
}

View File

@ -110,3 +110,35 @@ if ( !function_exists ('codepot_json_encode'))
}
if ( !function_exists ('codepot_delete_files'))
{
function codepot_delete_files($path, $del_dir = FALSE, $level = 0)
{
// Trim the trailing slash
$path = rtrim($path, DIRECTORY_SEPARATOR);
if ( ! $current_dir = @opendir($path))
return;
while(FALSE !== ($filename = @readdir($current_dir)))
{
if ($filename != "." && $filename != "..")
{
if (is_dir($path.DIRECTORY_SEPARATOR.$filename))
{
codepot_delete_files($path.DIRECTORY_SEPARATOR.$filename, $del_dir, $level + 1);
}
else
{
@unlink($path.DIRECTORY_SEPARATOR.$filename);
}
}
}
@closedir($current_dir);
if ($del_dir == TRUE /*&& $level > 0*/)
{
@rmdir($path);
}
}
}

View File

@ -101,8 +101,7 @@ class SubversionModel extends Model
$fileinfo['properties'] = $prop[$orgurl];
else $fileinfo['properties'] = NULL;
$fileinfo['fullpath'] = substr (
$info[0]['url'], strlen($info[0]['repos']));
$fileinfo['fullpath'] = substr ($info[0]['url'], strlen($info[0]['repos']));
$fileinfo['name'] = $info[0]['path'];
$fileinfo['type'] = 'dir';
$fileinfo['size'] = 0;
@ -234,7 +233,7 @@ class SubversionModel extends Model
$url = 'file://'.$this->_canonical_path(CODEPOT_SVNREPO_DIR."/{$projectid}/{$path}");
/* Compose a URL with a peg revision if a specific revision is given. However,
* It skipps composition if the path indicates the project root. Read the comment
* It skips composition if the path indicates the project root. Read the comment
* in getFile() to know more about this skipping.
*/
if ($rev != SVN_REVISION_HEAD && $path != '') $url = $url . '@' . $rev;
@ -839,6 +838,134 @@ class SubversionModel extends Model
@svn_auth_set_parameter (SVN_AUTH_PARAM_DEFAULT_USERNAME, $orguser);
return $result;
}
function _cloc_revision ($projectid, $path, $rev)
{
$orgurl = 'file://'.$this->_canonical_path(CODEPOT_SVNREPO_DIR."/{$projectid}/{$path}");
$workurl = ($path == '')? $orgurl: "{$orgurl}@"; // trailing @ for collision prevention
$info = @svn_info ($workurl, FALSE, $rev);
if ($info === FALSE || count($info) != 1)
{
// If a URL is at the root of repository and the url type is file://
// (e.g. file:///svnrepo/codepot/ where /svnrepo/codepot is a project root),
// some versions of libsvn end up with an assertion failure like
// ... libvvn_subr/path.c:114: svn_path_join: Assertion `svn_path_is_canonical(base, pool)' failed.
//
// Since the root directory is guaranteed to exist at the head revision,
// the information can be acquired without using a peg revision.
// In this case, a normal operational revision is used to work around
// the assertion failure. Other functions that has to deal with
// the root directory should implement this check to work around it.
//
if ($rev == SVN_REVISION_HEAD || $path == '') return FALSE;
// rebuild the URL with a peg revision and retry it.
$workurl = "{$orgurl}@{$rev}";
$info = @svn_info ($workurl, FALSE, $rev);
if ($info === FALSE || count($info) != 1) return FALSE;
}
if ($info[0]['kind'] == SVN_NODE_FILE) return FALSE;
// pass __FILE__ as the first argument so that tempnam creates a name
// in the system directory. __FILE__ can never be a valid directory.
$tfname = @tempnam(__FILE__, 'codepot-cloc-rev-');
if ($tfname === FALSE) return FALSE;
$actual_tfname = $tfname . '.d';
codepot_delete_files ($actual_tfname, TRUE); // delete the directory in case it exists
if (svn_checkout ($workurl, $actual_tfname, $rev, 0) === FALSE)
{
codepot_delete_files ($actual_tfname, TRUE);
@unlink ($tfname);
return FALSE;
}
$cloc_cmd = sprintf ('%s --quiet --csv --csv-delimiter=":" %s', CODEPOT_CLOC_COMMAND_PATH, $actual_tfname);
$cloc = @popen ($cloc_cmd, 'r');
if ($cloc === FALSE)
{
codepot_delete_files ($actual_tfname, TRUE);
@unlink ($tfname);
return FALSE;
}
$line_count = 0;
$cloc_data = array ();
while (!feof($cloc))
{
$line = @fgets ($cloc);
if ($line === FALSE) break;
$line_count++;
$line = trim($line);
if ($line_count >= 3)
{
$counter = explode (':', $line);
$cloc_data[$counter[1]] = array ($counter[0], $counter[2], $counter[3], $counter[4]);
}
}
@pclose ($cloc);
codepot_delete_files ($actual_tfname, TRUE);
@unlink ($tfname);
return $cloc_data;
}
function clocRev ($projectid, $path, $rev)
{
return $this->_cloc_revision ($projectid, $path, $rev);
}
function clocRevBySubdir ($projectid, $path, $rev)
{
$orgurl = 'file://'.$this->_canonical_path(CODEPOT_SVNREPO_DIR."/{$projectid}/{$path}");
$workurl = ($path == '')? $orgurl: "{$orgurl}@"; // trailing @ for collision prevention
$info = @svn_info ($workurl, FALSE, $rev);
if ($info === FALSE || count($info) != 1)
{
// If a URL is at the root of repository and the url type is file://
// (e.g. file:///svnrepo/codepot/ where /svnrepo/codepot is a project root),
// some versions of libsvn end up with an assertion failure like
// ... libvvn_subr/path.c:114: svn_path_join: Assertion `svn_path_is_canonical(base, pool)' failed.
//
// Since the root directory is guaranteed to exist at the head revision,
// the information can be acquired without using a peg revision.
// In this case, a normal operational revision is used to work around
// the assertion failure. Other functions that has to deal with
// the root directory should implement this check to work around it.
//
if ($rev == SVN_REVISION_HEAD || $path == '') return FALSE;
// rebuild the URL with a peg revision and retry it.
$workurl = "{$orgurl}@{$rev}";
$info = @svn_info ($workurl, FALSE, $rev);
if ($info === FALSE || count($info) != 1) return FALSE;
}
if ($info[0]['kind'] == SVN_NODE_FILE) return FALSE;
$lsinfo = @svn_ls ($workurl, $rev, FALSE, TRUE);
$cloc_data = array ();
foreach ($lsinfo as $key => $value)
{
if ($value['type'] == 'dir')
{
$cloc = $this->_cloc_revision ($projectid, "{$path}/{$key}", $rev);
if ($cloc === FALSE) return FALSE;
$cloc_data[$key] = $cloc;
}
}
return $cloc_data;
}
}
?>

View File

@ -172,7 +172,7 @@ print anchor ("code/fetch/{$project->id}/${xpar}{$revreq}", $this->lang->line('D
<a id="code_blame_mainarea_details_button" href='#'><?=$this->lang->line('Details')?></a>
</div>
<div id="code_blame_mainarea_result">
<div class="result" id="code_blame_mainarea_result">
<?php
$fileext = substr(strrchr($file['name'], '.'), 1);

View File

@ -129,7 +129,7 @@ $this->load->view (
if ($fileext == "") $fileext = "html"
?>
<div id="code_diff_mainarea_result">
<div class="result" id="code_diff_mainarea_result">
<?php
function format_diff ($a, $b, $css_class)
{

View File

@ -214,7 +214,7 @@ $this->load->view (
<a id="code_file_mainarea_details_button" href='#'><?=$this->lang->line('Details')?></a>
</div>
<div id="code_file_mainarea_result">
<div class="result" id="code_file_mainarea_result">
<?php
$fileext = substr(strrchr($file['name'], '.'), 1);

View File

@ -12,11 +12,127 @@
<script type="text/javascript" src="<?=base_url_make('/js/jquery-ui.min.js')?>"></script>
<link type="text/css" rel="stylesheet" href="<?=base_url_make('/css/jquery-ui.css')?>" />
<!--[if lte IE 8]><script type="text/javascript" src="<?=base_url_make('/js/excanvas.min.js')?>"></script><![endif]-->
<script type="text/javascript" src="<?=base_url_make('/js/jquery.flot.min.js')?>"></script>
<script type="text/javascript" src="<?=base_url_make('/js/jquery.flot.time.min.js')?>"></script>
<script type="text/javascript" src="<?=base_url_make('/js/jquery.flot.categories.min.js')?>"></script>
<script type="text/javascript" src="<?=base_url_make('/js/jquery.flot.stack.min.js')?>"></script>
<script type="text/javascript" src="<?=base_url_make('/js/jquery.flot.tickrotor.js')?>"></script>
<?php
$file_count = count($file['content']);
if ($revision <= 0)
{
$revreq = '';
$revreqroot = '';
}
else
{
$revreq = "/{$revision}";
$revreqroot = '/' . $this->converter->AsciiToHex('.') . $revreq;
}
?>
<script type="text/javascript">
function show_tooltip(id, x, y, contents) {
$('<div id="' + id + '">' + contents + '</div>').css( {
position: 'absolute',
display: 'none',
top: y + 5,
left: x + 5,
border: '1px solid #fdd',
padding: '2px',
'background-color': '#fee',
'font-size': '0.8em',
'font-family': 'inherit',
opacity: 0.80
}).appendTo("body").fadeIn(200);
}
function show_loc_graph (response)
{
var loc = $.parseJSON(response);
if (loc == null)
{
alert ('Invalid data received');
}
else
{
var blank = [];
for (var key in loc) blank.push ([ key, loc[key][1]] );
var comment = [];
for (var key in loc) comment.push ([ key, loc[key][2]] );
var code = [];
for (var key in loc) code.push ([ key, loc[key][3]] );
var dataset =
[
{ label: "blank", data: blank },
{ label: "comment", data: comment },
{ label: "code", data: code }
];
var options = {
series: {
stack: true,
shadowSize: 0,
bars: {
show: true,
fill: true,
align: "center",
barWidth: 0.8
},
lines: { show: false, fill: true },
points: { show: false }
},
grid: { hoverable: true, clickable: true },
xaxes: [
{ mode: "categories",
autoscaleMargin: 0.05,
rotateTicks: ((code.length >= 8)? 135: 0)
},
],
yaxes: { }
};
$("#code_folder_mainarea_result_info_loc_graph").width(550).height(400);
$.plot($("#code_folder_mainarea_result_info_loc_graph"), dataset, options);
var code_folder_mainarea_result_info_loc_graph_previous_point = null;
$("#code_folder_mainarea_result_info_loc_graph").bind("plothover", function (event, pos, item) {
if (item)
{
if (code_folder_mainarea_result_info_loc_graph_previous_point != item.datapoint)
{
code_folder_mainarea_result_info_loc_graph_previous_point = item.datapoint;
$("#code_folder_mainarea_result_info_loc_graph_tooltip").remove();
show_tooltip("code_folder_mainarea_result_info_loc_graph_tooltip", item.pageX, item.pageY - 20, item.datapoint[1]);
}
}
else
{
$("#code_folder_mainarea_result_info_loc_graph_tooltip").remove();
code_folder_mainarea_result_info_loc_graph_previous_point = null;
}
});
}
$("#code_folder_mainarea_result_info_loc_button").button("enable");
//$("#code_folder_mainarea_result_info_loc_progress" ).progressbar().hide();
}
<?php if ($file_count > 0): ?>
$(function () {
<?php
@ -44,6 +160,27 @@ $(function () {
"option", "label", "<?=$this->lang->line('Hide details')?>");
}
});
btn = $("#code_folder_mainarea_result_info_loc_button").button().click (function () {
$("#code_folder_mainarea_result_info_loc_button").button("disable");
//$("#code_folder_mainarea_result_info_loc_progress" ).progressbar("value", 0).show();
//function show_progress ()
//{
// var progress = $("#code_folder_mainarea_result_info_loc_progress");
// progress.progressbar ("value", progress.progressbar("value") + 1);
// setTimeout (show_progress, 1000);
//}
//setTimeout (show_progress, 1000);
var ajax_req = $.ajax ({
url: '<?=site_url()?>/graph/folder_loc_json/<?=$project->id?>/<?=$this->converter->AsciiToHex($headpath)?><?=$revreq?>',
context: document.body,
success: show_loc_graph
});
});
//$("#code_folder_mainarea_result_info_loc_progress" ).progressbar().hide();
});
<?php endif; ?>
</script>
@ -84,17 +221,6 @@ $this->load->view (
<div class="title">
<?php
if ($revision <= 0)
{
$revreq = '';
$revreqroot = '';
}
else
{
$revreq = "/{$revision}";
$revreqroot = '/' . $this->converter->AsciiToHex('.') . $revreq;
}
// print the main anchor for the root folder.
// let the anchor text be the project name.
print anchor (
@ -144,7 +270,11 @@ $this->load->view (
<?=form_close()?>
</div>
<div id="code_folder_mainarea_result">
<div class="result" id="code_folder_mainarea_result">
<div id="code_folder_mainarea_result_info_loc_progress"></div>
<div id="code_folder_mainarea_result_info_loc_graph">
</div>
<?php
function comp_files ($a, $b)
@ -308,7 +438,14 @@ $this->load->view (
print '</ul>';
}
print '<div class="title">LOC</div>';
print '<a id="code_folder_mainarea_result_info_loc_button" href="#">';
print $this->lang->line('Graph');
print '</a>';
print '</div>';
}
?>

View File

@ -78,7 +78,7 @@ $this->load->view (
<div class="menu" id="code_history_mainarea_menu">
</div> <!-- code_history_mainarea_menu -->
<div id="code_history_mainarea_result">
<div class="result" id="code_history_mainarea_result">
<?php
$xfullpath = $this->converter->AsciiToHex (($fullpath == '')? '.': $fullpath);

View File

@ -284,7 +284,7 @@ $history = $file['history'];
</div>
<div id="code_revision_mainarea_result">
<div class="result" id="code_revision_mainarea_result">
<div class="title"><?=$this->lang->line('Message')?>&nbsp;
<?php if ($can_edit): ?>

View File

@ -45,7 +45,7 @@ $this->load->view (
<div class="mainarea" id="file_home_mainarea">
<div class="title"><?=$this->lang->line('Files')?></div>
<div id="file_home_mainarea_result">
<div class="result" id="file_home_mainarea_result">
<?php
if (empty($files))
{

View File

@ -106,7 +106,7 @@ $this->load->view (
<div id="file_show_mainarea_result">
<div id="file_show_mainarea_wiki">
<div class="result" id="file_show_mainarea_wiki">
<pre id="file_show_mainarea_wiki_text" style="visibility: hidden">
<?php print htmlspecialchars($file->description); ?>
</pre>

View File

@ -21,7 +21,6 @@
<!--[if lte IE 8]><script type="text/javascript" src="<?=base_url_make('/js/excanvas.min.js')?>"></script><![endif]-->
<script type="text/javascript" src="<?=base_url_make('/js/jquery.min.js')?>"></script>
<script type="text/javascript" src="<?=base_url_make('/js/jquery-ui.min.js')?>"></script>
<script type="text/javascript" src="<?=base_url_make('/js/jquery.flot.min.js')?>"></script>
<script type="text/javascript" src="<?=base_url_make('/js/jquery.flot.time.min.js')?>"></script>
<script type="text/javascript" src="<?=base_url_make('/js/jquery.flot.categories.min.js')?>"></script>
@ -393,11 +392,17 @@ function show_all_graphs (response)
if (log == null)
{
alert ('Invalid data received');
return;
}
else if (log.length > 0)
{
show_commits_per_month_graph (log);
show_commits_per_user_graph (log);
}
else
{
//$("#graph_main_commits_per_month").text("No data available");
alert ('No data available');
}
}
function render_graphs()

View File

@ -154,7 +154,7 @@ $this->load->view (
</div>
<div id="issue_home_mainarea_result">
<div class="result" id="issue_home_mainarea_result">
<?php
if (empty($issues))
{

View File

@ -274,7 +274,7 @@ foreach ($urls as $url)
<?=htmlspecialchars($project->name)?>
</div>
<div id="project_home_mainarea_wiki">
<div class="result" id="project_home_mainarea_wiki">
<pre id="project_home_mainarea_wiki_text" style="visibility: hidden">
<?php print htmlspecialchars($project->description); ?>
</pre>

View File

@ -46,6 +46,8 @@ $this->load->view (
<div class="mainarea" id="site_catalog_mainarea">
<div class="result" id="site_catalog_mainarea_result">
<ul>
<?php
foreach ($sites as $site)
@ -56,6 +58,7 @@ foreach ($sites as $site)
}
?>
</ul>
</div>
</div> <!-- site_catalog_mainarea -->

View File

@ -286,7 +286,7 @@ foreach ($latest_projects as $project)
<div id="site_home_mainarea_wiki">
<div class="result" id="site_home_mainarea_wiki">
<pre id="site_home_mainarea_wiki_text" style="visibility: hidden">
<?php print htmlspecialchars($site->text); ?>
</pre>

View File

@ -88,9 +88,6 @@ body {
.content .taskbar a:active {
}
.content .taskbar form {
margin: 0;
}
@ -116,6 +113,10 @@ body {
vertical-align: middle;
}
.content .mainarea .result {
min-height: 30em;
}
.content .mainarea form input:focus {
background-color: #E7E8E7;
outline: 0;