GitDiffParser   A
last analyzed

Complexity

Total Complexity 20

Size/Duplication

Total Lines 118
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 61
c 1
b 0
f 0
dl 0
loc 118
rs 10
wmc 20

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
B parseDiffLines() 0 28 6
A splitOnNewLine() 0 11 3
B parse() 0 47 10
1
<?php
2
// src/VersionControl/GitCommandBundle/GitCommands/GitDiffParser.php
3
4
/*
5
 * This file is part of the GitCommandBundle package.
6
 *
7
 * (c) Paul Schweppe <[email protected]>
8
 *
9
 * For the full copyright and license information, please view the LICENSE
10
 * file that was distributed with this source code.
11
 */
12
13
namespace VersionControl\GitCommandBundle\GitCommands;
14
15
use VersionControl\GitCommandBundle\Entity\GitDiff;
16
use VersionControl\GitCommandBundle\Entity\GitDiffLine;
17
18
/**
19
 * Parses git diff command response.
20
 *
21
 * @author Paul Schweppe <[email protected]>
22
 */
23
class GitDiffParser
24
{
25
    protected $lines;
26
27
    protected $lineCount;
28
29
    /**
30
     * @param string $string
31
     */
32
    public function __construct($string)
33
    {
34
        $this->lines = $this->splitOnNewLine($string, false);
35
        $this->lineCount = count($this->lines);
36
    }
37
38
    public function parse()
39
    {
40
        $diffs = array();
41
        $diff = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $diff is dead and can be removed.
Loading history...
42
        $collected = array();
43
44
        for ($i = 0; $i < $this->lineCount; ++$i) {
45
            if (preg_match('(^---\\s+(?P<file>.+))', $this->lines[$i], $matchFileA) &&
46
                preg_match('(^\\+\\+\\+\\s+(?P<file>.+))', $this->lines[$i + 1], $matchFileB)) {
47
48
                //Second iteration
49
                if (count($collected) > 0 && count($diffs) > 0) {
50
                    $lastDiff = end($diffs);
51
                    $diffLines = $this->parseDiffLines($collected);
52
                    $lastDiff->setDiffLines($diffLines);
53
                    reset($diffs);
54
                }
55
56
                //All iteration
57
                $diff = new GitDiff();
58
                $diff->setFileA($matchFileA['file']);
59
                $diff->setFileB($matchFileB['file']);
60
                $diffs[] = $diff;
61
62
                $collected = array();
63
64
                ++$i;
65
66
                if ($i >= 300000) {
67
                    break;
68
                }
69
            } else {
70
                if (preg_match('/^(?:diff --git |index [\da-f\.]+|[+-]{3} [ab])/', $this->lines[$i])) {
71
                    continue;
72
                }
73
                $collected[] = $this->lines[$i];
74
            }
75
        }
76
77
        if (count($collected) > 0 && count($diffs) > 0) {
78
            $lastDiff = end($diffs);
79
            $diffLines = $this->parseDiffLines($collected);
80
            $lastDiff->setDiffLines($diffLines);
81
            reset($diffs);
82
        }
83
84
        return $diffs;
85
    }
86
87
    /**
88
     * @param array $lines
89
     *
90
     * @return array
91
     */
92
    private function parseDiffLines(array $lines)
93
    {
94
        $section = array();
0 ignored issues
show
Unused Code introduced by
The assignment to $section is dead and can be removed.
Loading history...
95
        $diffLines = array();
96
        $lineNumber = 0;
97
        foreach ($lines as $line) {
98
            $diffLine = new GitDiffLine($line);
99
            if (preg_match('/^@@\s+-(?P<start>\d+)(?:,\s*(?P<startrange>\d+))?\s+\+(?P<end>\d+)(?:,\s*(?P<endrange>\d+))?\s+@@/', $line, $match)) {
100
                $section = array(
101
                    $match['start'],
102
                    isset($match['startrange']) ? max(1, $match['startrange']) : 1,
103
                    $match['end'],
104
                    isset($match['endrange']) ? max(1, $match['endrange']) : 1,
105
                );
106
                $diffLine->setLineNumber('...');
107
                $lineNumber = $match['start'];
108
            } else {
109
                if ($diffLine->getType() === GitDiffLine::REMOVED) {
110
                    $diffLine->setLineNumber('');
111
                } else {
112
                    $diffLine->setLineNumber($lineNumber);
113
                    ++$lineNumber;
114
                }
115
            }
116
            $diffLines[] = $diffLine;
117
        }
118
119
        return $diffLines;
120
    }
121
122
    /**
123
     * Splits a block of text on newlines and returns an array.
124
     *
125
     * @param string $text       Text to split
126
     * @param bool   $trimSpaces If true then each line is trimmed of white spaces. Default true
127
     *
128
     * @return array Array of lines
129
     */
130
    protected function splitOnNewLine($text, $trimSpaces = true)
131
    {
132
        if (!trim($text)) {
133
            return array();
134
        }
135
        $lines = preg_split('/$\R?^/m', $text);
136
        if ($trimSpaces) {
137
            return array_map('trim', $lines);
0 ignored issues
show
Bug introduced by
It seems like $lines can also be of type false; however, parameter $arr1 of array_map() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

137
            return array_map('trim', /** @scrutinizer ignore-type */ $lines);
Loading history...
138
        }
139
140
        return $lines;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $lines could also return false which is incompatible with the documented return type array. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
141
    }
142
}
143