view release on metacpan or search on metacpan
lib/Analizo/Batch/Job.pm view on Meta::CPAN
# ['field2', 10],
# ]
#
# In this case, B<metadata_hashref> must return the following:
#
# {
# 'field1' => 'value1',
# 'field2' => 10,
# }
#
sub metadata_hashref($) {
my ($self) = @_;
my %hash = map { $_->[0] => $_->[1] } @{$self->metadata()};
return \%hash;
}
sub execute {
my ($self) = @_;
$self->prepare();
lib/Analizo/Batch/Job.pm view on Meta::CPAN
if (!defined $metrics) {
$metrics = Analizo::Metrics->new(model => $self->model);
$metrics->data();
$self->cache->set($metrics_cache_key, $metrics);
}
$self->metrics($metrics);
$self->cleanup();
}
sub project_name($) {
my ($self) = @_;
return basename($self->directory);
}
sub cache($) {
my ($self) = @_;
$self->{cache} ||= CHI->new(driver => 'File', root_dir => _get_cache_dir());
}
sub _get_cache_dir {
if ($ENV{ANALIZO_CACHE}) {
return $ENV{ANALIZO_CACHE};
}
# automated test environment should not mess with the real cache
lib/Analizo/Batch/Job.pm view on Meta::CPAN
if ($program_path[0] eq '.') {
shift @program_path;
}
if ($program_path[0] eq 't') {
return tempdir(CLEANUP => 1);
}
return File::Spec->catfile(File::HomeDir->my_home, '.cache', 'analizo', $Analizo::VERSION)
}
sub tree_id($) {
my ($self) = @_;
my @input = sort($self->apply_filters('.'));
my $sha1 = Digest::SHA->new;
foreach my $input_file (@input) {
$sha1->addfile($input_file);
}
return $sha1->hexdigest;
}
1;
lib/Analizo/Batch/Job/Git.pm view on Meta::CPAN
use File::Spec;
use Digest::SHA qw/ sha1_hex /;
use File::Copy::Recursive qw(dircopy);
use File::Path qw(remove_tree);
sub new {
my ($class, $directory, $id, $data) = @_;
$class->SUPER::new(directory => $directory, actual_directory => $directory, id => $id, data => $data);
}
sub batch($$) {
my ($self, $batch) = @_;
if ($batch) {
$self->{finder} = sub { $batch->find($_[0]); };
$batch->share_filters_with($self);
}
return undef;
}
sub parallel_prepare {
my ($self) = @_;
lib/Analizo/Batch/Output/CSV.pm view on Meta::CPAN
$self->_write_details($job->id, $details);
}
}
my $__encoders = {
_default => sub { $_[0] },
ARRAY => sub { '"' . join(';', @{$_[0]}) . '"' },
HASH => sub { '"' . join(';', map { join(':', $_, $_[0]->{$_}) } sort(keys(%{$_[0]}))) . '"' },
};
sub _encode_value($) {
my ($value) = @_;
my $encoder = $__encoders->{ref($value)} || $__encoders->{_default};
return &$encoder($value);
}
sub _extract_short_names_of_metrics {
my $metrics_instance = Analizo::Metrics->new;
my @short_names = ();
my %metrics_names = $metrics_instance->list_of_metrics();
lib/Analizo/Batch/Output/DB.pm view on Meta::CPAN
package Analizo::Batch::Output::DB;
use strict;
use warnings;
use parent qw( Analizo::Batch::Output );
use DBI;
use Digest::SHA qw(sha1_hex);
sub database($) {
my ($self) = @_;
my $db = $self->file || 'output.sqlite3';
if ($db =~ /^dbi:/) {
return $db;
} else {
return 'dbi:SQLite:' . $db;
}
}
sub push($$) {
my ($self, $job) = @_;
my $project_id = $self->_add_project($job->project_name);
my $developer_id = $self->_add_developer($job);
my $commit_id = $self->_add_commit($job, $project_id, $developer_id);
$self->_add_modules($job, $commit_id, $project_id);
}
sub flush($) {
my ($self) = @_;
$self->{dbh}->disconnect();
}
sub _find_row_id($$@) {
my ($self, $sql, @data) = @_;
my $statement_id = 'st_find_' . sha1_hex($sql); # is this SHA1 needed at all?
$self->{$statement_id} ||= $self->{dbh}->prepare($sql);
my $list = $self->{dbh}->selectall_arrayref($self->{$statement_id}, {}, @data);
if (scalar(@$list) == 0) {
return undef;
} else {
return $list->[0]->[0];
}
}
sub _add_project($$) {
my ($self, $project) = @_;
$self->{st_add_project} ||= $self->{dbh}->prepare('INSERT INTO projects (name) values(?)');
my $project_id = $self->_find_project($project);
if (! $project_id) {
$self->{st_add_project}->execute($project);
$project_id = $self->_find_project($project);
}
return $project_id;
}
sub _find_project($$) {
my ($self, $project) = @_;
return $self->_find_row_id('SELECT id from projects where name = ?', $project);
}
sub _add_developer($$) {
my ($self, $job) = @_;
my $metadata = $job->metadata_hashref();
my $name = $metadata->{author_name};
my $email = $metadata->{author_email};
# FIXME unstested
if (!$name || !$email) {
return undef;
}
lib/Analizo/Batch/Output/DB.pm view on Meta::CPAN
$self->{st_add_developer} ||= $self->{dbh}->prepare('INSERT INTO developers (name,email) VALUES (?,?)');
my $developer_id = $self->_find_developer($name, $email);
if (! $developer_id) {
$self->{st_add_developer}->execute($name, $email);
$developer_id = $self->_find_developer($name, $email);
}
return $developer_id;
}
sub _find_developer($$$) {
my ($self, $name, $email) = @_;
return $self->_find_row_id('SELECT id FROM developers WHERE name = ? AND email = ?', $name, $email);
}
sub _add_commit($$$$) {
my ($self, $job, $project_id, $developer_id) = @_;
unless ($self->_find_row_id('SELECT id FROM commits where id = ?', $job->id)) {
my $metadata = $job->metadata_hashref;
my $previous_commit_id = $metadata->{previous_commit_id};
my $date = $metadata->{author_date};
my ($summary, $details) = ({}, {});
if ($job->metrics) {
($summary, $details) = $job->metrics->data();
}
my ($metric_placeholders_sql, $metric_column_names_sql, @metric_values) = _metrics_sql($summary, _project_metric_columns());
$self->{st_insert_commit} ||= $self->{dbh}->prepare("INSERT INTO commits (id, project_id,developer_id,previous_commit_id,date,$metric_column_names_sql) VALUES(?,?,?,?,?,$metric_placeholders_sql)");
$self->{st_insert_commit}->execute($job->id, $project_id, $developer_id, $previous_commit_id, $date, @metric_values);
}
return $job->id;
}
sub _add_modules($$$$) {
my ($self, $job, $commit_id, $project_id) = @_;
my $metadata = $job->metadata_hashref();
my %module_versions = ();
if ($metadata->{files}) {
for my $file (keys(%{$metadata->{files}})) {
for my $module ($job->model->module_by_file($file)) {
unless($module_versions{$module}) {
my $module_id = $self->_add_module($module, $project_id);
lib/Analizo/Batch/Output/DB.pm view on Meta::CPAN
if ($statuses =~ /^A+$/) {
$self->_mark_as_added($commit_id, $module_version_id);
} elsif ($statuses !~ /^D+$/) {
$self->_mark_as_modified($commit_id, $module_version_id);
}
}
}
}
}
sub _add_module($$$) {
my ($self, $module, $project_id) = @_;
my $module_id = $self->_find_module($module, $project_id);
if (!$module_id) {
$self->{st_add_module} ||= $self->{dbh}->prepare('INSERT INTO modules (name, project_id) values (?,?)');
$self->{st_add_module}->execute($module, $project_id);
$module_id = $self->_find_module($module, $project_id);
}
return $module_id;
}
sub _find_module($$$) {
my ($self, $module, $project_id) = @_;
return $self->_find_row_id('SELECT id FROM modules WHERE name = ? AND project_id = ?', $module, $project_id);
}
sub _module_version_id {
my @file_ids = @_;
my $module_version_id;
if (scalar(@file_ids) == 1) {
$module_version_id = $file_ids[0];
} else {
lib/Analizo/Batch/Output/DB.pm view on Meta::CPAN
$self->{st_add_module_version} ||= $self->{dbh}->prepare($statement);
$self->{st_add_module_version}->execute($module_version_id, $module_id, @metric_values);
}
$self->{st_link_commit_and_module_version} ||= $self->{dbh}->prepare('INSERT INTO commits_module_versions (commit_id,module_version_id) VALUES (?,?)');
$self->{st_link_commit_and_module_version}->execute($commit_id, $module_version_id);
return $module_version_id;
}
sub _mark_as_added($$$) {
my ($self, $commit_id, $module_version_id) = @_;
$self->{st_mark_as_added} ||= $self->{dbh}->prepare('UPDATE commits_module_versions SET added = 1 WHERE commit_id = ? AND module_version_id = ?');
$self->{st_mark_as_added}->execute($commit_id, $module_version_id);
}
sub _mark_as_modified($$$) {
my ($self, $commit_id, $module_version_id) = @_;
$self->{st_mark_as_modified} ||= $self->{dbh}->prepare('UPDATE commits_module_versions SET modified = 1 WHERE commit_id = ? AND module_version_id = ?');
$self->{st_mark_as_modified}->execute($commit_id, $module_version_id);
}
sub _metrics_sql($@) {
my ($metrics_hash, @metric_columns) = @_;
my $metric_placeholders_sql = join(',', map { '?' } @metric_columns);
my $metric_column_names_sql = join(',', @metric_columns);
my @metric_values = map { $metrics_hash->{$_} } @metric_columns;
return ($metric_placeholders_sql, $metric_column_names_sql, @metric_values)
}
# Initializes the database
#
# TODO the current approach of feeding DDL SQL statements directly to the
# database handle might not be good enough, since the SQL being written might
# not be portable to other databases than SQLite. It would be nice to have
# something similar to the rails migrations DSL here.
sub initialize($) {
my ($self) = @_;
$self->{dbh} = DBI->connect($self->database, undef, undef, { RaiseError => 1, InactiveDestroy => 1});
# assume that if there is a table called `analizo_metadata`, then the database was already initialized
if (!grep { $_ =~ /analizo_metadata/ } $self->{dbh}->tables()) {
for my $statement (ddl_statements()) {
$statement =~ s/\@\@MODULE_METRICS\@\@/_metric_columns_ddl(_module_metric_columns())/egm;
$statement =~ s/\@\@PROJECT_METRICS\@\@/_metric_columns_ddl(_project_metric_columns())/egm;
$statement =~ s/\@\@NUMERIC_AUTOINC_PK\@\@/_numeric_autoinc_pk($self->database)/egm;
$self->{dbh}->do($statement);
}
}
}
my $DDL_INITIALIZED = 0;
my @DDL_STATEMENTS = ();
sub ddl_statements($) {
if (!$DDL_INITIALIZED) {
my $sql = '';
while (my $line = <DATA>) {
$sql .= $line;
if ($line =~ /;\s*$/) {
# SQL statement is ready
CORE::push @DDL_STATEMENTS, $sql;
$sql = '';
}
}
$DDL_INITIALIZED = 1;
}
return @DDL_STATEMENTS;
}
use Analizo::Metrics;
use Analizo::Model;
my $__metric_columns = undef;
sub _metric_columns() {
if (!$__metric_columns) {
my $metrics = Analizo::Metrics->new(model => Analizo::Model->new);
my %module_metrics = $metrics->list_of_metrics();
my @module_metrics= keys(%module_metrics);
my %project_metrics = $metrics->list_of_global_metrics();
my @project_metrics = keys(%project_metrics);
$__metric_columns = {
module => \@module_metrics,
project => \@project_metrics,
};
}
return $__metric_columns;
}
sub _module_metric_columns() {
return @{ _metric_columns()->{module} };
}
sub _project_metric_columns() {
return @{ _metric_columns()->{project} };
}
sub _metric_columns_ddl {
my @columns = @_;
my $ddl = join(",\n ", map { "$_ REAL"} @columns);
return $ddl;
}
my %NUMERIC_AUTOINC_PK = (
'sqlite' => 'INTEGER PRIMARY KEY AUTOINCREMENT',
'pg' => 'SERIAL PRIMARY KEY',
);
sub _numeric_autoinc_pk($) {
my ($database) = @_;
my $dbtype = lc($database);
$dbtype =~ s/^dbi:(.*):.*/$1/;
my $sql = $NUMERIC_AUTOINC_PK{$dbtype};
die("Database $dbtype is not supported!") if (!defined($sql));
return $sql;
}
1;
lib/Analizo/Batch/Runner.pm view on Meta::CPAN
package Analizo::Batch::Runner;
use parent qw(Class::Accessor::Fast);
sub new {
my ($class, @args) = @_;
return bless { @args }, $class;
}
sub run($$$) {
my ($self, $batch, $output) = @_;
$output->initialize();
$self->actually_run($batch, $output);
$output->flush();
}
# must be implemented by subclasses. Will receive as argument:
#
# * the batch to be run
# * the output object
lib/Analizo/Filter/Client.pm view on Meta::CPAN
push @{$self->{filters}}, @new_filters;
}
return $self->{filters};
}
sub has_filters {
my ($self) = @_;
return exists($self->{filters}) && exists($self->{filters}->[0]);
}
sub share_filters_with($$) {
my ($self, $other) = @_;
$other->{filters} = $self->{filters};
}
sub exclude {
my ($self, @dirs) = @_;
if (!$self->{excluding_dirs}) {
$self->{excluding_dirs} = 1;
$self->filters(Analizo::LanguageFilter->new);
}
t/Analizo/Batch/Output/DB.t view on Meta::CPAN
}
sub setup : Test(setup) {
system("mkdir", "-p", $TMPDIR);
}
sub teardown : Test(teardown) {
system("rm", "-rf", $TMPDIR);
}
sub table_created_ok($$) {
my ($db, $table) = @_;
my $dbh = DBI->connect("dbi:SQLite:$db");
my $TABLE = uc($table);
$table = lc($table);
my @tables = $dbh->tables();
my $projects_table = scalar(grep { lc($_) =~ /$table/ } @tables);
ok($projects_table, "must create $TABLE table");
}
sub select_ok($$$) {
my ($db, $query, $count) = @_;
my $dbh = DBI->connect("dbi:SQLite:$db");
my $rows = $dbh->selectall_arrayref($query);
my $row_count = scalar(@$rows);
is($row_count, $count, "[$query] returned $row_count rows instead of exactly $count");
}
sub select_one_ok($$) {
my ($db, $query) = @_;
select_ok($db, $query, 1);
}
__PACKAGE__->runtests;