Completed
Push — master ( 08d342...72ccac )
by Richard
04:51
created

Engine::run()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 18
ccs 16
cts 16
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 14
nc 3
nop 0
crap 3
1
<?php
2
/******************************************************************************
3
 * An implementation of dicto (scg.unibe.ch/dicto) in and for PHP.
4
 * 
5
 * Copyright (c) 2016 Richard Klees <[email protected]>
6
 *
7
 * This software is licensed under The MIT License. You should have received 
8
 * a copy of the license along with the code.
9
 */
10
11
namespace Lechimp\Dicto\App;
12
13
use Lechimp\Dicto\Indexer\InsertTwice;
14
use Lechimp\Dicto\Indexer\IndexerFactory;
15
use Lechimp\Dicto\Analysis\ReportGenerator;
16
use Lechimp\Dicto\Analysis\AnalyzerFactory;
17
use Lechimp\Dicto\Analysis\Index;
18
use Lechimp\Dicto\Indexer\Insert;
19
use Lechimp\Dicto\Graph;
20
use Psr\Log\LoggerInterface as Log;
21
22
/**
23
 * The Engine of the App drives the analysis process.
24
 */
25
class Engine {
26
    /**
27
     * @var Log
28
     */
29
    protected $log;
30
31
    /**
32
     * @var Config
33
     */
34
    protected $config;
35
36
    /**
37
     * @var DBFactory
38
     */
39
    protected $db_factory;
40
41
    /**
42
     * @var IndexerFactory
43
     */
44
    protected $indexer_factory;
45
46
    /**
47
     * @var AnalyzerFactory
48
     */
49
    protected $analyzer_factory;
50
51
    /**
52
     * @var ReportGenerator
53
     */
54
    protected $report_generator;
55
56
    /**
57
     * @var SourceStatus
58
     */
59
    protected $source_status;
60
61 9
    public function __construct( Log $log
62
                               , Config $config
63
                               , DBFactory $db_factory
64
                               , IndexerFactory $indexer_factory
65
                               , AnalyzerFactory $analyzer_factory
66
                               , ReportGenerator $report_generator
67
                               , SourceStatus $source_status
68
                               ) {
69 9
        $this->log = $log;
70 9
        $this->config = $config;
71 9
        $this->db_factory = $db_factory;
72 9
        $this->indexer_factory = $indexer_factory;
73 9
        $this->analyzer_factory = $analyzer_factory;
74 9
        $this->report_generator = $report_generator;
75 9
        $this->source_status = $source_status;
76 9
    }
77
78
    /**
79
     * Run the analysis.
80
     * 
81
     * @return null
82
     */
83 8
    public function run() {
84 8
        $index_db_path = $this->index_database_path();
85 8
        if (!$this->db_factory->index_db_exists($index_db_path)) {
86 7
            $index = $this->build_index();
87 7
            $this->run_indexing($index);
88 7
            if ($index instanceof InsertTwice) {
89 1
                $index_db = $this->force_app_index_db($index->second());
90 1
                $index_db->write_cached_inserts();
91 1
                $index = $this->force_graph_index_db($index->first());
92 1
            }
93 7
        }
94
        else {
95 1
            $index_db = $this->db_factory->load_index_db($index_db_path);
96 1
            $this->log->notice("Reading index from database '$index_db_path'...");
97 1
            $index = $this->read_index_from($index_db);
98
        }
99 8
        $this->run_analysis($index);
100 8
    }
101
102 8
    protected function index_database_path() {
103 8
        $commit_hash = $this->source_status->commit_hash();
104 8
        return $this->config->project_storage()."/$commit_hash.sqlite";
105
    }
106
107 7
    protected function run_indexing(Insert $index) {
108 7
        $this->log->notice("Building index...");
109 7
        $indexer = $this->indexer_factory->build($index);
110 7
        $this->with_time_measurement
111
            ( function ($s) { return "Indexing took $s seconds to run."; }
112
            , function () use ($indexer) {
113 7
                $indexer->index_directory
114 7
                    ( $this->config->project_root()
115 7
                    , $this->config->analysis_ignore()
116 7
                    );
117 7
            });
118 7
    }
119
120 8
    protected function run_analysis(Index $index) {
121 8
        $this->log->notice("Running analysis...");
122 8
        $commit_hash = $this->source_status->commit_hash();
123 8
        $this->report_generator->begin_run($commit_hash);
124 8
        $analyzer = $this->analyzer_factory->build($index, $this->report_generator);
125 8
        $this->with_time_measurement
126
            ( function ($s) { return "Analysis took $s seconds to run."; }
127
            , function () use ($analyzer) {
128 8
                $analyzer->run();
129 8
            });
130 8
        $this->report_generator->end_run();
131 8
    }
132
133 7
    protected function build_index() {
134 7
        if ($this->config->analysis_store_index()) {
135 1
            $index_db_path = $this->index_database_path();
136 1
            $index_db = $this->db_factory->build_index_db($index_db_path);
137 1
            $this->log->notice("Writing index to database '$index_db_path'...");
138 1
            return new InsertTwice(new Graph\IndexDB, $index_db);
139
        }
140
141 6
        return new Graph\IndexDB;
142
    }
143
144
    /**
145
     * @return  Graph\IndexDB
146
     */
147
    protected function read_index_from(IndexDB $db) {
148
        $index = null;
149
        $this->with_time_measurement
150
            ( function ($s) { return "Loading the index took $s seconds."; }
151
            , function () use ($db, &$index) {
152
                $index = $db->to_graph_index();
153
            });
154
        return $this->force_graph_index_db($index);
155
    }
156
157 8
    protected function with_time_measurement(\Closure $message, \Closure $what) {
158 8
        $start_time = microtime(true);
159 8
        $what();
160 8
        $time_elapsed_secs = microtime(true) - $start_time;
161 8
        $this->log->notice($message($time_elapsed_secs));
162 8
    }
163
164
    /**
165
     * @param   mixed   $index
166
     * @return  Graph\IndexDB
167
     */
168 1
    protected function force_graph_index_db($index) {
169 1
        if ($index instanceof Graph\IndexDB) {
170 1
            return $index;
171
        }
172
        else {
173
            throw new \LogicException(
174
                "Expected index to be of type Graph\IndexDB, but it is '".
175
                get_class($index)."'");
176
        }
177
    }
178
179
    /**
180
     * @param   mixed   $index
181
     * @return  IndexDB
182
     */
183 1
    protected function force_app_index_db($index) {
184 1
        if ($index instanceof IndexDB) {
185 1
            return $index;
186
        }
187
        else {
188
            throw new \LogicException(
189
                "Expected index to be of type App\IndexDB, but it is '".
190
                get_class($index)."'");
191
        }
192
    }
193
}
194