Completed
Push — develop ( 5f7df1...9cb564 )
by Matteo
10s
created

Commit::parseOutputLines()   C

Complexity

Conditions 8
Paths 65

Size

Total Lines 38
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 37
CRAP Score 8

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 38
ccs 37
cts 37
cp 1
rs 5.3846
cc 8
eloc 29
nc 65
nop 1
crap 8
1
<?php
2
/**
3
 * GitElephant - An abstraction layer for git written in PHP
4
 * Copyright (C) 2013  Matteo Giachino
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program.  If not, see [http://www.gnu.org/licenses/].
18
 */
19
20
namespace GitElephant\Objects;
21
22
use \GitElephant\Command\BranchCommand;
23
use \GitElephant\Command\MainCommand;
24
use \GitElephant\Command\RevListCommand;
25
use \GitElephant\Command\RevParseCommand;
26
use \GitElephant\Command\ShowCommand;
27
use \GitElephant\Objects\Commit\Message;
28
use \GitElephant\Repository;
29
30
/**
31
 * The Commit object represent a commit
32
 *
33
 * @author Matteo Giachino <[email protected]>
34
 */
35
class Commit implements TreeishInterface, \Countable
36
{
37
    /**
38
     * @var \GitElephant\Repository
39
     */
40
    private $repository;
41
42
    /**
43
     * @var string
44
     */
45
    private $ref;
46
47
    /**
48
     * sha
49
     *
50
     * @var string
51
     */
52
    private $sha;
53
54
    /**
55
     * tree
56
     *
57
     * @var string
58
     */
59
    private $tree;
60
61
    /**
62
     * the commit parents
63
     *
64
     * @var array
65
     */
66
    private $parents;
67
68
    /**
69
     * the Author instance for author
70
     *
71
     * @var \GitElephant\Objects\Author
72
     */
73
    private $author;
74
75
    /**
76
     * the Author instance for committer
77
     *
78
     * @var \GitElephant\Objects\Author
79
     */
80
    private $committer;
81
82
    /**
83
     * the Message instance
84
     *
85
     * @var \GitElephant\Objects\Commit\Message
86
     */
87
    private $message;
88
89
    /**
90
     * the date for author
91
     *
92
     * @var \DateTime
93
     */
94
    private $datetimeAuthor;
95
96
    /**
97
     * the date for committer
98
     *
99
     * @var \Datetime
100
     */
101
    private $datetimeCommitter;
102
103
    /**
104
     * Class constructor
105
     *
106
     * @param \GitElephant\Repository $repository the repository
107
     * @param string                  $treeish    a treeish reference
108
     */
109 35
    private function __construct(Repository $repository, $treeish = 'HEAD')
110
    {
111 35
        $this->repository = $repository;
112 35
        $this->ref = $treeish;
113 35
        $this->parents = array();
114 35
    }
115
116
    /**
117
     * factory method to create a commit
118
     *
119
     * @param Repository    $repository repository instance
120
     * @param string        $message    commit message
121
     * @param bool          $stageAll   automatically stage the dirty working tree. Alternatively call stage() on the repo
122
     * @param string|Author $author     override the author for this commit
123
     *
124
     * @throws \RuntimeException
125
     * @throws \Symfony\Component\Process\Exception\LogicException
126
     * @throws \InvalidArgumentException
127
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
128
     * @throws \Symfony\Component\Process\Exception\RuntimeException
129
     * @return Commit
130
     */
131 3
    public static function create(Repository $repository, $message, $stageAll = false, $author = null)
132
    {
133 3
        $repository->getCaller()->execute(MainCommand::getInstance($repository)->commit($message, $stageAll, $author));
134
135 3
        return $repository->getCommit();
136
    }
137
138
    /**
139
     * pick an existing commit
140
     *
141
     * @param Repository              $repository repository
142
     * @param TreeishInterface|string $treeish    treeish
143
     *
144
     * @throws \RuntimeException
145
     * @throws \Symfony\Component\Process\Exception\RuntimeException
146
     * @return Commit
147
     */
148 16
    public static function pick(Repository $repository, $treeish = null)
149
    {
150 16
        $commit = new self($repository, $treeish);
0 ignored issues
show
Bug introduced by
It seems like $treeish defined by parameter $treeish on line 148 can also be of type null or object<GitElephant\Objects\TreeishInterface>; however, GitElephant\Objects\Commit::__construct() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
151 16
        $commit->createFromCommand();
152
153 16
        return $commit;
154
    }
155
156
    /**
157
     * static generator to generate a single commit from output of command.show service
158
     *
159
     * @param \GitElephant\Repository $repository  repository
160
     * @param array                   $outputLines output lines
161
     *
162
     * @return Commit
163
     */
164 20
    public static function createFromOutputLines(Repository $repository, $outputLines)
165
    {
166 20
        $commit = new self($repository);
167 20
        $commit->parseOutputLines($outputLines);
168
169 20
        return $commit;
170
    }
171
172
    /**
173
     * get the commit properties from command
174
     *
175
     * @see ShowCommand::commitInfo
176
     */
177 16
    public function createFromCommand()
178
    {
179 16
        $command = ShowCommand::getInstance($this->getRepository())->showCommit($this->ref);
180 16
        $outputLines = $this->getCaller()->execute($command, true, $this->getRepository()->getPath())->getOutputLines();
181 16
        $this->parseOutputLines($outputLines);
182 16
    }
183
184
    /**
185
     * get the branches this commit is contained in
186
     *
187
     * @see BranchCommand::contains
188
     */
189
    public function getContainedIn()
190
    {
191
        $command = BranchCommand::getInstance($this->getRepository())->contains($this->getSha());
192
193
        return array_map('trim', (array)$this->getCaller()->execute($command)->getOutputLines(true));
194
    }
195
196
    /**
197
     * number of commits that lead to this one
198
     *
199
     * @throws \RuntimeException
200
     * @throws \Symfony\Component\Process\Exception\LogicException
201
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
202
     * @throws \Symfony\Component\Process\Exception\RuntimeException
203
     * @return int|void
204
     */
205 3
    public function count()
206
    {
207 3
        $command = RevListCommand::getInstance($this->getRepository())->commitPath($this);
208
209 3
        return count($this->getCaller()->execute($command)->getOutputLines(true));
210
    }
211
212 1
    public function getDiff()
213
    {
214 1
        return $this->getRepository()->getDiff($this);
215
    }
216
217
    /**
218
     * parse the output of a git command showing a commit
219
     *
220
     * @param array $outputLines output lines
221
     */
222 35
    private function parseOutputLines($outputLines)
223
    {
224 35
        $message = '';
225 35
        foreach ($outputLines as $line) {
226 35
            $matches = array();
227 35
            if (preg_match('/^commit (\w+)$/', $line, $matches) > 0) {
228 35
                $this->sha = $matches[1];
229 35
            }
230 35
            if (preg_match('/^tree (\w+)$/', $line, $matches) > 0) {
231 35
                $this->tree = $matches[1];
232 35
            }
233 35
            if (preg_match('/^parent (\w+)$/', $line, $matches) > 0) {
234 24
                $this->parents[] = $matches[1];
235 24
            }
236 35
            if (preg_match('/^author (.*) <(.*)> (\d+) (.*)$/', $line, $matches) > 0) {
237 35
                $author = new Author();
238 35
                $author->setName($matches[1]);
239 35
                $author->setEmail($matches[2]);
240 35
                $this->author = $author;
241 35
                $date = \DateTime::createFromFormat('U O', $matches[3] . ' ' . $matches[4]);
242 35
                $date->modify($date->getOffset() . ' seconds');
243 35
                $this->datetimeAuthor = $date;
244 35
            }
245 35
            if (preg_match('/^committer (.*) <(.*)> (\d+) (.*)$/', $line, $matches) > 0) {
246 35
                $committer = new Author();
247 35
                $committer->setName($matches[1]);
248 35
                $committer->setEmail($matches[2]);
249 35
                $this->committer = $committer;
250 35
                $date = \DateTime::createFromFormat('U O', $matches[3] . ' ' . $matches[4]);
251 35
                $date->modify($date->getOffset() . ' seconds');
252 35
                $this->datetimeCommitter = $date;
253 35
            }
254 35
            if (preg_match('/^    (.*)$/', $line, $matches)) {
255 35
                $message[] = $matches[1];
256 35
            }
257 35
        }
258 35
        $this->message = new Message($message);
259 35
    }
260
261
    /**
262
     * Returns true if the commit is a root commit. Usually the first of the repository
263
     *
264
     * @return bool
265
     */
266 3
    public function isRoot()
267
    {
268 3
        return count($this->parents) == 0;
269
    }
270
271
    /**
272
     * toString magic method
273
     *
274
     * @return string the sha
275
     */
276 8
    public function __toString()
277
    {
278 8
        return $this->sha;
279
    }
280
281
    /**
282
     * @return \GitElephant\Command\Caller\Caller
283
     */
284 16
    private function getCaller()
285
    {
286 16
        return $this->getRepository()->getCaller();
287
    }
288
289
    /**
290
     * Repository setter
291
     *
292
     * @param \GitElephant\Repository $repository repository variable
293
     */
294
    public function setRepository($repository)
295
    {
296
        $this->repository = $repository;
297
    }
298
299
    /**
300
     * Repository getter
301
     *
302
     * @return \GitElephant\Repository
303
     */
304 16
    public function getRepository()
305
    {
306 16
        return $this->repository;
307
    }
308
309
    /**
310
     * author getter
311
     *
312
     * @return Author
313
     */
314 4
    public function getAuthor()
315
    {
316 4
        return $this->author;
317
    }
318
319
    /**
320
     * committer getter
321
     *
322
     * @return Author
323
     */
324 4
    public function getCommitter()
325
    {
326 4
        return $this->committer;
327
    }
328
329
    /**
330
     * message getter
331
     *
332
     * @return \GitElephant\Objects\Commit\Message
333
     */
334 11
    public function getMessage()
335
    {
336 11
        return $this->message;
337
    }
338
339
    /**
340
     * parent getter
341
     *
342
     * @return mixed
343
     */
344 2
    public function getParents()
345
    {
346 2
        return $this->parents;
347
    }
348
349
    /**
350
     * sha getter
351
     *
352
     * @param bool $short short version
353
     *
354
     * @return mixed
355
     */
356 22
    public function getSha($short = false)
357
    {
358 22
        return $short ? substr($this->sha, 0, 7) : $this->sha;
359
    }
360
361
    /**
362
     * tree getter
363
     *
364
     * @return mixed
365
     */
366 3
    public function getTree()
367
    {
368 3
        return $this->tree;
369
    }
370
371
    /**
372
     * datetimeAuthor getter
373
     *
374
     * @return mixed
375
     */
376 4
    public function getDatetimeAuthor()
377
    {
378 4
        return $this->datetimeAuthor;
379
    }
380
381
    /**
382
     * datetimeCommitter getter
383
     *
384
     * @return \DateTime
385
     */
386 4
    public function getDatetimeCommitter()
387
    {
388 4
        return $this->datetimeCommitter;
389
    }
390
391
    /**
392
     * rev-parse command - often used to return a commit tag.
393
     *
394
     * @param array         $options the options to apply to rev-parse
395
     *
396
     * @throws \RuntimeException
397
     * @throws \InvalidArgumentException
398
     * @throws \Symfony\Component\Process\Exception\RuntimeException
399
     * @return array
400
     */
401 1
    public function revParse(Array $options = array())
0 ignored issues
show
Coding Style introduced by
As per coding-style, PHP keywords should be in lowercase; expected array, but found Array.
Loading history...
402
    {
403 1
        $c = RevParseCommand::getInstance()->revParse($this, $options);
404 1
        $caller = $this->repository->getCaller();
405 1
        $caller->execute($c);
406
407 1
        return array_map('trim', $caller->getOutputLines(true));
408
    }
409
}
410