Completed
Pull Request — develop (#109)
by
unknown
11:25
created

Repository::getCacheKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 0
cts 0
cp 0
rs 10
cc 1
eloc 3
nc 1
nop 0
crap 2
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;
21
22
use \GitElephant\Command\FetchCommand;
23
use \GitElephant\Command\PullCommand;
24
use \GitElephant\Command\PushCommand;
25
use \GitElephant\Command\RemoteCommand;
26
use GitElephant\Command\ResetCommand;
27
use \GitElephant\Command\Caller\Caller;
28
use \GitElephant\Objects\Author;
29
use \GitElephant\Objects\Remote;
30
use \GitElephant\Objects\Tree;
31
use \GitElephant\Objects\Branch;
32
use \GitElephant\Objects\Tag;
33
use \GitElephant\Objects\Object;
34
use \GitElephant\Objects\Diff\Diff;
35
use \GitElephant\Objects\Commit;
36
use \GitElephant\Objects\Log;
37
use \GitElephant\Objects\LogRange;
38
use \GitElephant\Objects\TreeishInterface;
39
use \GitElephant\Command\MainCommand;
40
use \GitElephant\Command\BranchCommand;
41
use \GitElephant\Command\MergeCommand;
42
use \GitElephant\Command\RevParseCommand;
43
use \GitElephant\Command\TagCommand;
44
use \GitElephant\Command\LogCommand;
45
use \GitElephant\Command\CloneCommand;
46
use \GitElephant\Command\CatFileCommand;
47
use \GitElephant\Command\LsTreeCommand;
48
use \GitElephant\Command\SubmoduleCommand;
49
use GitElephant\Objects\TreeObject;
50
use \GitElephant\Status\Status;
51
use \GitElephant\Status\StatusIndex;
52
use \GitElephant\Status\StatusWorkingTree;
53
use \Symfony\Component\Filesystem\Filesystem;
54
use \Symfony\Component\Finder\Finder;
55
use \Symfony\Component\Finder\SplFileInfo;
56
use Illuminate\Support\Facades\Cache;
57
58
/**
59
 * Repository
60
 *
61
 * Base Class for repository operations
62
 *
63
 * @author Matteo Giachino <[email protected]>
64
 * @author Dhaval Patel <[email protected]>
65
 */
66
class Repository
67
{
68
    /**
69
     * the repository path
70
     *
71
     * @var string
72
     */
73
    private $path;
74
75
    /**
76
     * the caller instance
77
     *
78
     * @var \GitElephant\Command\Caller\Caller
79
     */
80
    private $caller;
81
82
    /**
83
     * A general repository name
84
     *
85
     * @var string $name the repository name
86
     */
87
    private $name;
88
89
    /**
90
     * A list of global configs to apply to every command
91
     * 
92
     * @var array
93
     */
94
    private $globalConfigs = array();
95
96
    /**
97
     * A list of global options to apply to every command
98
     * 
99
     * @var array
100
     */
101
    private $globalOptions = array();
102
103
    /**
104
     * A list of global arguments to apply to every command
105
     * 
106
     * @var array
107
     */
108
    private $globalCommandArguments = array();
109
110
    /**
111
     * Class constructor
112
     *
113
     * @param string         $repositoryPath the path of the git repository
114
     * @param GitBinary|null $binary         the GitBinary instance that calls the commands
115
     * @param string         $name           a repository name
116
     *
117
     * @throws Exception\InvalidRepositoryPathException
118 103
     */
119
    public function __construct($repositoryPath, GitBinary $binary = null, $name = null)
120 103
    {
121 103
        if (is_null($binary)) {
122 103
            $binary = new GitBinary();
123
        }
124 103
125 103
        $this->path = $repositoryPath;
126 103
        $this->caller = new Caller($binary, $repositoryPath);
127 103
        $this->name = $name;
128
    }
129
130
    /**
131
     * Factory method
132
     *
133
     * @param string         $repositoryPath the path of the git repository
134
     * @param GitBinary|null $binary         the GitBinary instance that calls the commands
135
     * @param string         $name           a repository name
136
     *
137
     * @return \GitElephant\Repository
138 102
     */
139 1
    public static function open($repositoryPath, GitBinary $binary = null, $name = null)
140 102
    {
141
        return new self($repositoryPath, $binary, $name);
142
    }
143
144
    /**
145
     * create a repository from a remote git url, or a local filesystem
146
     * and save it in a temp folder
147
     *
148
     * @param string|Repository $git            the git remote url, or the filesystem path
149
     * @param null              $repositoryPath path
150
     * @param GitBinary         $binary         binary
151
     * @param null              $name           repository name
152
     *
153
     * @throws \RuntimeException
154
     * @throws \Symfony\Component\Filesystem\Exception\IOException
155
     * @return Repository
156 1
     */
157
    public static function createFromRemote($git, $repositoryPath = null, GitBinary $binary = null, $name = null)
158 1
    {
159 1
        if (null === $repositoryPath) {
160 1
            $tempDir = realpath(sys_get_temp_dir());
161 1
            $repositoryPath = sprintf('%s%s%s', $tempDir, DIRECTORY_SEPARATOR, sha1(uniqid()));
162 1
            $fs = new Filesystem();
163 1
            $fs->mkdir($repositoryPath);
164 1
        }
165 1
        $repository = new Repository($repositoryPath, $binary, $name);
166
        if ($git instanceof Repository) {
167
            $git = $git->getPath();
168 1
        }
169 1
        $repository->cloneFrom($git, $repositoryPath);
0 ignored issues
show
Bug introduced by
It seems like $repositoryPath defined by sprintf('%s%s%s', $tempD...ARATOR, sha1(uniqid())) on line 161 can also be of type string; however, GitElephant\Repository::cloneFrom() does only seem to accept null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
170
        $repository->checkoutAllRemoteBranches();
171 1
172
        return $repository;
173
    }
174
175
    /**
176
     * Init the repository
177
     *
178
     * @param bool $bare created a bare repository
179
     *
180
     * @throws \RuntimeException
181
     * @throws \Symfony\Component\Process\Exception\LogicException
182
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
183
     * @throws \Symfony\Component\Process\Exception\RuntimeException
184
     * @return Repository
185 92
     */
186
    public function init($bare = false)
187 92
    {
188
        $this->caller->execute(MainCommand::getInstance($this)->init($bare));
189 92
190
        return $this;
191
    }
192
193
    /**
194
     * Stage the working tree content
195
     *
196
     * @param string|Object $path the path to store
197
     *
198
     * @throws \RuntimeException
199
     * @throws \Symfony\Component\Process\Exception\LogicException
200
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
201
     * @throws \Symfony\Component\Process\Exception\RuntimeException
202
     * @return Repository
203 88
     */
204
    public function stage($path = '.')
205 88
    {
206
        $this->caller->execute(MainCommand::getInstance($this)->add($path));
0 ignored issues
show
Bug introduced by
It seems like $path defined by parameter $path on line 204 can also be of type object<GitElephant\Objects\Object>; however, GitElephant\Command\MainCommand::add() 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...
207 88
208
        return $this;
209
    }
210
211
    /**
212
     * Unstage a tree content
213
     *
214
     * @param string|Object $path the path to unstage
215
     *
216
     * @throws \RuntimeException
217
     * @throws \Symfony\Component\Process\Exception\LogicException
218
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
219
     * @throws \Symfony\Component\Process\Exception\RuntimeException
220
     * @return Repository
221 2
     */
222
    public function unstage($path)
223 2
    {
224
        $this->caller->execute(MainCommand::getInstance($this)->unstage($path), true, null, array(0, 1));
0 ignored issues
show
Bug introduced by
It seems like $path defined by parameter $path on line 222 can also be of type object<GitElephant\Objects\Object>; however, GitElephant\Command\MainCommand::unstage() 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...
225 2
226
        return $this;
227
    }
228
229
    /**
230
     * Move a file/directory
231
     *
232
     * @param string|Object $from source path
233
     * @param string|Object $to   destination path
234
     *
235
     * @throws \RuntimeException
236
     * @throws \Symfony\Component\Process\Exception\LogicException
237
     * @throws \InvalidArgumentException
238
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
239
     * @throws \Symfony\Component\Process\Exception\RuntimeException
240
     * @return Repository
241 1
     */
242
    public function move($from, $to)
243 1
    {
244
        $this->caller->execute(MainCommand::getInstance($this)->move($from, $to));
245 1
246
        return $this;
247
    }
248
249
    /**
250
     * Remove a file/directory
251
     *
252
     * @param string|Object $path      the path to remove
253
     * @param bool          $recursive recurse
254
     * @param bool          $force     force
255
     *
256
     * @throws \RuntimeException
257
     * @throws \Symfony\Component\Process\Exception\LogicException
258
     * @throws \InvalidArgumentException
259
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
260
     * @throws \Symfony\Component\Process\Exception\RuntimeException
261
     * @return Repository
262 1
     */
263
    public function remove($path, $recursive = false, $force = false)
264 1
    {
265
        $this->caller->execute(MainCommand::getInstance($this)->remove($path, $recursive, $force));
266 1
267
        return $this;
268
    }
269
270
    /**
271
     * Commit content to the repository, eventually staging all unstaged content
272
     *
273
     * @param string        $message  the commit message
274
     * @param bool          $stageAll whether to stage on not everything before commit
275
     * @param string|null   $ref      the reference to commit to (checkout -> commit -> checkout previous)
276
     * @param string|Author $author   override the author for this commit
277
     *
278
     * @throws \RuntimeException
279
     * @throws \InvalidArgumentException
280
     * @throws \Symfony\Component\Process\Exception\RuntimeException
281
     * @return Repository
282 85
     */
283
    public function commit($message, $stageAll = false, $ref = null, $author = null, $allowEmpty = false)
284 85
    {
285 85
        $currentBranch = null;
286 1
        if (! is_null($ref)) {
287 1
            $currentBranch = $this->getMainBranch();
288 1
            $this->checkout($ref);
289 85
        }
290 83
        if ($stageAll) {
291 83
            $this->stage();
292 85
        }
293 85
        $this->caller->execute(MainCommand::getInstance($this)->commit($message, $stageAll, $author, $allowEmpty));
294 1
        if (! is_null($ref)) {
295 1
            $this->checkout($currentBranch);
0 ignored issues
show
Bug introduced by
It seems like $currentBranch defined by null on line 285 can be null; however, GitElephant\Repository::checkout() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
296
        }
297 85
298
        return $this;
299
    }
300
301
    /**
302
     * rev-parse command - often used to return a commit tag.
303
     *
304
     * @param array                  $options the options to apply to rev-parse
305
     * @param string|Object|Commit   $arg the argument (may be a branch head, etc)
306
     *
307
     * @throws \RuntimeException
308
     * @throws \InvalidArgumentException
309
     * @throws \Symfony\Component\Process\Exception\RuntimeException
310
     * @return array
311 1
     */
312
    public function revParse($arg = null, 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...
313 1
    {
314
        $this->caller->execute(RevParseCommand::getInstance()->revParse($arg, $options));
0 ignored issues
show
Bug introduced by
It seems like $arg defined by parameter $arg on line 312 can also be of type object<GitElephant\Objects\Commit> or object<GitElephant\Objects\Object>; however, GitElephant\Command\RevParseCommand::revParse() does only seem to accept object<GitElephant\Objects\Branch>|string|null, 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...
315 1
316
        return array_map('trim', $this->caller->getOutputLines(true));
317
    }
318
319
    /**
320
     * Check if this is a bare repository
321
     * @return boolean
322 1
     */
323
    public function isBare()
324 1
    {
325 1
        $options = array(RevParseCommand::OPTION_IS_BARE_REPOSIORY);
326
        $this->caller->execute(RevParseCommand::getInstance()->revParse(null, $options));
327 1
328
        return trim($this->caller->getOutput()) === 'true';
329
    }
330
331
    /**
332
     * @param TreeishInterface|Commit|string $arg
333
     * @param array $options
334 2
     */
335
    public function reset($arg,$options)
0 ignored issues
show
Coding Style introduced by
Expected 1 space between comma and argument "$options"; 0 found
Loading history...
336 2
    {
337 2
        $this->caller->execute(ResetCommand::getInstance($this)->reset($arg,$options));
338
    }
339
340
    /**
341
     * Get the repository status
342
     *
343
     * @return Status
344 5
     */
345
    public function getStatus()
346 5
    {
347
        return Status::get($this);
348
    }
349
350
    /**
351
     * @return StatusWorkingTree
352 1
     */
353
    public function getWorkingTreeStatus()
354 1
    {
355
        return StatusWorkingTree::get($this);
356
    }
357
358
    /**
359
     * @return StatusIndex
360 4
     */
361
    public function getIndexStatus()
362 4
    {
363
        return StatusIndex::get($this);
364
    }
365
    
366
    /**
367
     * isClean Return true if the repository is not dirty.
368
     * 
369
     * @return boolean
370
     */
371
    public function isClean()
372
    {
373
        return $this->getStatus()->all()->isEmpty();
374
    }
375
    
376
    /**
377
     * isDirty Return true if the repository has some modified files.
378
     * 
379
     * @return boolean
380
     */
381
    public function isDirty()
382
    {
383
        return !$this->isClean();
384
    }
385
386
    /**
387
     * Get the repository status as a string
388
     *
389
     * @throws \RuntimeException
390
     * @throws \Symfony\Component\Process\Exception\LogicException
391
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
392
     * @throws \Symfony\Component\Process\Exception\RuntimeException
393
     * @return array
394 4
     */
395
    public function getStatusOutput() {
396 4
397
    	$cacheKey = $this->getCacheKey();
398 4
	    $cacheTag = $this->getCacheTag();
399
		if(Cache::tags($cacheTag)->has($cacheKey)) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after IF keyword; 0 found
Loading history...
Coding Style introduced by
Blank line found at start of control structure
Loading history...
400
401
			return Cache::tags($cacheTag)->get($cacheKey);
402
		}
403
404
        $this->caller->execute(MainCommand::getInstance($this)->status());
405
		$outputLines = array_map('trim', $this->caller->getOutputLines());
406
		Cache::tags($cacheTag)->put($cacheKey, $outputLines, 15);
407
408
        return $outputLines;
409
    }
410
411 27
    /**
412
     * Create a new branch
413 27
     *
414
     * @param string $name       the new branch name
415 27
     * @param null   $startPoint the reference to create the branch from
416
     *
417
     * @throws \RuntimeException
418
     * @throws \Symfony\Component\Process\Exception\RuntimeException
419
     * @return Repository
420
     */
421
    public function createBranch($name, $startPoint = null)
422
    {
423
        Branch::create($this, $name, $startPoint);
424
425
        return $this;
426
    }
427
428
    /**
429
     * Delete a branch by its name
430
     * This function change the state of the repository on the filesystem
431 1
     *
432
     * @param string $name  The branch to delete
433 1
     * @param bool   $force Force the delete
434
     *
435 1
     * @throws \RuntimeException
436
     * @throws \Symfony\Component\Process\Exception\LogicException
437
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
438
     * @throws \Symfony\Component\Process\Exception\RuntimeException
439
     * @return Repository
440
     */
441
    public function deleteBranch($name, $force = false)
442
    {
443
        $this->caller->execute(BranchCommand::getInstance($this)->delete($name, $force));
444
445
        return $this;
446
    }
447
448
    /**
449
     * An array of Branch objects
450
     *
451 17
     * @param bool $namesOnly return an array of branch names as a string
452
     * @param bool $all       lists also remote branches
453 17
     *
454 17
     * @throws \RuntimeException
455 6
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
456 6
     * @throws \Symfony\Component\Process\Exception\LogicException
457 6
     * @throws \InvalidArgumentException
458 6
     * @throws \Symfony\Component\Process\Exception\RuntimeException
459
     * @return array
460 6
     */
461 6
    public function getBranches($namesOnly = false, $all = false)
462
    {
463 6
    	$cacheKey = $this->getCacheKey();
464 6
    	$cacheTag = $this->getCacheTag();
465 14
    	if(Cache::tags($cacheTag)->has($cacheKey)) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after IF keyword; 0 found
Loading history...
Coding Style introduced by
Blank line found at start of control structure
Loading history...
466 14
467 14
    		return Cache::tags($cacheTag)->get($cacheKey);
468 14
	    }
469 14
470 14
        $branches = array();
471
        if ($namesOnly) {
472
            $outputLines = $this->caller->execute(
473 17
                BranchCommand::getInstance($this)->listBranches($all, true)
474
            )->getOutputLines(true);
475
            $branches = array_map(
476
                function ($v) {
477
                    return ltrim($v, '* ');
478
                },
479
                $outputLines
480
            );
481
        } else {
482
            $outputLines = $this->caller->execute(
483
                BranchCommand::getInstance($this)->listBranches($all)
484 5
            )->getOutputLines(true);
485
            foreach ($outputLines as $branchLine) {
486 5
                $branches[] = Branch::createFromOutputLine($this, $branchLine);
487 5
            }
488
        }
489 5
490
	    Cache::tags($cacheTag)->put($cacheKey, $branches, 15);
491 5
        return $branches;
492 5
    }
493
494 5
    /**
495
     * Return the actually checked out branch
496
     *
497
     * @throws \RuntimeException
498
     * @throws \InvalidArgumentException
499
     * @throws \Symfony\Component\Process\Exception\RuntimeException
500
     * @return Objects\Branch
501
     */
502
    public function getMainBranch()
503
    {
504
    	$cacheKey = $this->getCacheKey();
505
	    $cacheTag = $this->getCacheTag();
506
	    if(Cache::tags($cacheTag)->has($cacheKey)) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after IF keyword; 0 found
Loading history...
Coding Style introduced by
Blank line found at start of control structure
Loading history...
507 9
508
	    	return Cache::tags($cacheTag)->get($cacheKey);
509
	    }
510 9
511 9
        $filtered = array_filter(
512 9
            $this->getBranches(),
513
            function (Branch $branch) {
514 4
                return $branch->getCurrent();
515
            }
516 1
        );
517
        sort($filtered);
518
519
        Cache::tags($cacheTag)->put($cacheKey, $filtered[0], 15);
520
        return $filtered[0];
521
    }
522
523
    /**
524
     * Retrieve a Branch object by a branch name
525
     *
526
     * @param string $name The branch name
527
     *
528
     * @throws \RuntimeException
529 1
     * @throws \InvalidArgumentException
530
     * @throws \Symfony\Component\Process\Exception\RuntimeException
531 1
     * @return null|Branch
532 1
     */
533 1
    public function getBranch($name)
534 1
    {
535 1
        /** @var Branch $branch */
536 1
        foreach ($this->getBranches() as $branch) {
537 1
            if ($branch->getName() == $name) {
538 1
                return $branch;
539 1
            }
540
        }
541 1
542 1
        return null;
543 1
    }
544 1
545 1
    /**
546
     * Checkout all branches from the remote and make them local
547 1
     *
548
     * @param string $remote remote to fetch from
549
     *
550
     * @throws \RuntimeException
551
     * @throws \InvalidArgumentException
552
     * @throws \Symfony\Component\Process\Exception\RuntimeException
553
     * @return Repository
554
     */
555
    public function checkoutAllRemoteBranches($remote = 'origin')
556
    {
557
        $actualBranch = $this->getMainBranch();
558
        $actualBranches = $this->getBranches(true, false);
559
        $allBranches = $this->getBranches(true, true);
560
        $realBranches = array_filter(
561
            $allBranches,
562
            function ($branch) use ($actualBranches) {
563 2
                return !in_array($branch, $actualBranches)
564
                && preg_match('/^remotes(.+)$/', $branch)
565
                && !preg_match('/^(.+)(HEAD)(.*?)$/', $branch);
566 2
            }
567 2
        );
568 2
        foreach ($realBranches as $realBranch) {
569 2
            $this->checkout(str_replace(sprintf('remotes/%s/', $remote), '', $realBranch));
570 2
        }
571
        $this->checkout($actualBranch);
572
573
        return $this;
574 2
    }
575
576 2
    /**
577 1
     * Merge a Branch in the current checked out branch
578 1
     *
579 2
     * @param Objects\Branch $branch  The branch to merge in the current checked out branch
580 2
     * @param string         $message The message for the merge commit, if merge is 3-way
581 1
     * @param string         $mode    The merge mode: ff-only, no-ff or auto
582
     *
583
     * @throws \RuntimeException
584 2
     * @throws \Symfony\Component\Process\Exception\LogicException
585
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
586 2
     * @throws \Symfony\Component\Process\Exception\RuntimeException
587
     * @return Repository
588
     */
589
    public function merge(Branch $branch, $message = '', $mode = 'auto')
590
    {
591
        $valid_modes = array(
592
            'auto',    // deafult git behavior
593
            'ff-only', // force fast forward merge
594
            'no-ff',   // force 3-way merge
595
        );
596
        if (!in_array($mode, $valid_modes)) {
597
            throw new \Symfony\Component\Process\Exception\InvalidArgumentException("Invalid merge mode: $mode.");
598
        }
599
600
        $options = array();
601 25
        switch ($mode) {
602
            case 'ff-only':
603 25
                $options[] = MergeCommand::MERGE_OPTION_FF_ONLY;
604
                break;
605 25
            case 'no-ff':
606
                $options[] = MergeCommand::MERGE_OPTION_NO_FF;
607
                break;
608
        }
609
610
        $this->caller->execute(MergeCommand::getInstance($this)->merge($branch, $message, $options));
611
612
        return $this;
613
    }
614
615
    /**
616
     * Create a new tag
617
     * This function change the state of the repository on the filesystem
618 2
     *
619
     * @param string $name       The new tag name
620 2
     * @param null   $startPoint The reference to create the tag from
621 1
     * @param null   $message    the tag message
622 1
     *
623 1
     * @throws \RuntimeException
624
     * @throws \Symfony\Component\Process\Exception\RuntimeException
625
     * @return Repository
626 2
     */
627
    public function createTag($name, $startPoint = null, $message = null)
628
    {
629
        Tag::create($this, $name, $startPoint, $message);
630
631
        return $this;
632
    }
633
634
    /**
635
     * Delete a tag by it's name or by passing a Tag object
636
     * This function change the state of the repository on the filesystem
637
     *
638
     * @param string|Tag $tag The tag name or the Tag object
639
     *
640
     * @throws \RuntimeException
641 1
     * @throws \Symfony\Component\Process\Exception\RuntimeException
642
     * @return Repository
643 1
     */
644
    public function deleteTag($tag)
645 1
    {
646
        if ($tag instanceof Tag) {
647
            $tag->delete();
648
        } else {
649
            Tag::pick($this, $tag)->delete();
650
        }
651
652
        return $this;
653
    }
654
655
    /**
656
     * add a git submodule to the repository
657
     *
658
     * @param string $gitUrl git url of the submodule
659
     * @param string $path   path to register the submodule to
660
     *
661
     * @throws \RuntimeException
662
     * @throws \Symfony\Component\Process\Exception\LogicException
663
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
664
     * @throws \Symfony\Component\Process\Exception\RuntimeException
665
     * @return Repository
666
     */
667
    public function addSubmodule($gitUrl, $path = null)
668
    {
669
        $this->caller->execute(SubmoduleCommand::getInstance($this)->add($gitUrl, $path));
670
671
        return $this;
672
    }
673
674
    /**
675
     * initialize submodules
676
     *
677
     * @param  string $path init only submodules at the specified path
678
     *
679
     * @return Repository
680
     */
681
    public function initSubmodule($path = null)
682
    {
683
        $this->caller->execute(SubmoduleCommand::getInstance($this)->init($path));
684
        return $this;
685
    }
686 2
687
    /**
688 2
     * update submodules
689 2
     *
690 2
     * @param  bool   $recursive update recursively
691 2
     * @param  bool   $init      init before update
692 2
     * @param  bool   $force     force the checkout as part of update
693 2
     * @param  string $path      update only a specific submodule path
694 2
     *
695
     * @return Repository
696 2
     */
697
    public function updateSubmodule($recursive = false, $init = false, $force = false, $path = null)
698
    {
699
        $this->caller->execute(SubmoduleCommand::getInstance($this)->update($recursive, $init, $force, $path));
700
        return $this;
701
    }
702
703
    /**
704
     * Gets an array of Tag objects
705
     *
706
     * @throws \RuntimeException
707
     * @throws \Symfony\Component\Process\Exception\LogicException
708 27
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
709
     * @throws \Symfony\Component\Process\Exception\RuntimeException
710 27
     * @return array
711 27
     */
712 27
    public function getTags()
713 27
    {
714
        $tags = array();
715 5
        $this->caller->execute(TagCommand::getInstance($this)->listTags());
716
        foreach ($this->caller->getOutputLines() as $tagString) {
717 1
            if ($tagString != '') {
718
                $tags[] = new Tag($this, trim($tagString));
719
            }
720
        }
721
722
        return $tags;
723
    }
724
725
    /**
726
     * Return a tag object
727
     *
728 1
     * @param string $name The tag name
729
     *
730 1
     * @throws \RuntimeException
731 1
     * @throws \Symfony\Component\Process\Exception\RuntimeException
732 1
     * @return Tag|null
733 1
     */
734 1
    public function getTag($name)
735
    {
736
        $tagFinderOutput = $this->caller->execute(TagCommand::getInstance()->listTags())->getOutputLines(true);
737 1
        foreach ($tagFinderOutput as $line) {
738 1
            if ($line === $name) {
739
                return new Tag($this, $name);
740 1
            }
741 1
        }
742
743 1
        return null;
744
    }
745
746
    /**
747
     * Return the last created tag
748
     *
749
     * @throws \LogicException
750
     * @throws \RuntimeException
751
     * @throws \InvalidArgumentException
752
     * @return Tag|null
753
     */
754
    public function getLastTag()
755
    {
756 1
        $finder = Finder::create()
757
                  ->files()
758 1
                  ->in(sprintf('%s/.git/refs/tags', $this->path))
759 1
                  ->sortByChangedTime();
760
        if ($finder->count() == 0) {
761 1
            return null;
762 1
        }
763 1
        $files = iterator_to_array($finder->getIterator(), false);
764 1
        $files = array_reverse($files);
765
        /** @var $firstFile SplFileInfo */
766 1
        $firstFile = $files[0];
767
        $tagName = $firstFile->getFilename();
768 1
769
        return Tag::pick($this, $tagName);
770
    }
771
772
    /**
773
     * Try to get a branch or a tag by its name.
774
     *
775
     * @param string $name the reference name (a tag name or a branch name)
776
     *
777
     * @throws \RuntimeException
778
     * @throws \InvalidArgumentException
779 13
     * @throws \Symfony\Component\Process\Exception\RuntimeException
780
     * @return \GitElephant\Objects\Tag|\GitElephant\Objects\Branch|null
781 13
     */
782
    public function getBranchOrTag($name)
783 13
    {
784
        if (in_array($name, $this->getBranches(true))) {
785
            return new Branch($this, $name);
786
        }
787
        $tagFinderOutput = $this->caller->execute(TagCommand::getInstance($this)->listTags())->getOutputLines(true);
788
        foreach ($tagFinderOutput as $line) {
789
            if ($line === $name) {
790
                return new Tag($this, $name);
791
            }
792
        }
793
794
        return null;
795 3
    }
796
797 3
    /**
798
     * Return a Commit object
799 3
     *
800
     * @param string $ref The commit reference
801
     *
802
     * @throws \RuntimeException
803
     * @return Objects\Commit
804
     */
805
    public function getCommit($ref = 'HEAD')
806
    {
807
        $commit = Commit::pick($this, $ref);
808
809
        return $commit;
810
    }
811
812
    /**
813 20
     * count the commit to arrive to the given treeish
814
     *
815 20
     * @param string $start
816
     *
817
     * @throws \RuntimeException
818
     * @throws \Symfony\Component\Process\Exception\RuntimeException
819
     * @return int|void
820
     */
821
    public function countCommits($start = 'HEAD')
822
    {
823
        $commit = Commit::pick($this, $start);
824
825
        return $commit->count();
826
    }
827
828
    /**
829
     * Get a log for a ref
830
     *
831
     * @param string|TreeishInterface|array $ref         the treeish to check, as a string, as an object or as an array
832
     * @param string|Object                 $path        the physical path to the tree relative to the repository root
833
     * @param int|null                      $limit       limit to n entries
834
     * @param int|null                      $offset      skip n entries
835
     * @param boolean|false                 $firstParent skip commits brought in to branch by a merge
836
     *
837
     * @return \GitElephant\Objects\Log
838
     */
839
    public function getLog($ref = 'HEAD', $path = null, $limit = 10, $offset = null, $firstParent = false)
840
    {
841
        return new Log($this, $ref, $path, $limit, $offset, $firstParent);
0 ignored issues
show
Bug introduced by
It seems like $path defined by parameter $path on line 839 can also be of type object<GitElephant\Objects\Object> or string; however, GitElephant\Objects\Log::__construct() does only seem to accept null, 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...
Bug introduced by
It seems like $offset defined by parameter $offset on line 839 can also be of type integer; however, GitElephant\Objects\Log::__construct() does only seem to accept null, 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...
842
    }
843
844
    /**
845
     * Get a log for a range ref
846
     *
847
     * @param string        $refStart
848
     * @param string        $refEnd
849
     * @param string|Object $path        the physical path to the tree relative to the repository root
850
     * @param int|null      $limit       limit to n entries
851
     * @param int|null      $offset      skip n entries
852
     * @param boolean|false $firstParent skip commits brought in to branch by a merge
853
     *
854
     * @return \GitElephant\Objects\LogRange
855
     */
856
    public function getLogRange($refStart, $refEnd, $path = null, $limit = 10, $offset = null, $firstParent = false)
857
    {
858
        // Handle when clients provide bad start reference on branch creation
859 3
        if (preg_match('~^[0]+$~', $refStart)) {
860
            return new Log($this, $refEnd, $path, $limit, $offset, $firstParent);
0 ignored issues
show
Bug introduced by
It seems like $path defined by parameter $path on line 856 can also be of type object<GitElephant\Objects\Object> or string; however, GitElephant\Objects\Log::__construct() does only seem to accept null, 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...
Bug introduced by
It seems like $offset defined by parameter $offset on line 856 can also be of type integer; however, GitElephant\Objects\Log::__construct() does only seem to accept null, 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...
Bug Best Practice introduced by
The return type of return new \GitElephant\...$offset, $firstParent); (GitElephant\Objects\Log) is incompatible with the return type documented by GitElephant\Repository::getLogRange of type GitElephant\Objects\LogRange.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
861 3
        }
862
863 3
        // Handle when clients provide bad end reference on branch deletion
864
        if (preg_match('~^[0]+$~', $refEnd)) {
865
            $refEnd = $refStart;
866
        }
867
868
        return new LogRange($this, $refStart, $refEnd, $path, $limit, $offset, $firstParent);
0 ignored issues
show
Bug introduced by
It seems like $path defined by parameter $path on line 856 can also be of type object<GitElephant\Objects\Object> or string; however, GitElephant\Objects\LogRange::__construct() does only seem to accept null, 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...
Bug introduced by
It seems like $offset defined by parameter $offset on line 856 can also be of type integer; however, GitElephant\Objects\LogRange::__construct() does only seem to accept null, 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...
869
    }
870
871
    /**
872
     * Get a log for an object
873
     *
874
     * @param \GitElephant\Objects\Object             $obj    The Object instance
875
     * @param null|string|\GitElephant\Objects\Branch $branch The branch to read from
876
     * @param int                                     $limit  Limit to n entries
877
     * @param int|null                                $offset Skip n entries
878
     *
879 24
     * @throws \RuntimeException
880
     * @throws \Symfony\Component\Process\Exception\LogicException
881 24
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
882
     * @throws \Symfony\Component\Process\Exception\RuntimeException
883
     * @return \GitElephant\Objects\Log
884 24
     */
885
    public function getObjectLog(Object $obj, $branch = null, $limit = 1, $offset = null)
886 24
    {
887
        $command = LogCommand::getInstance($this)->showObjectLog($obj, $branch, $limit, $offset);
888
889
        return Log::createFromOutputLines($this, $this->caller->execute($command)->getOutputLines());
890
    }
891
892
    /**
893
     * Checkout a branch
894
     * This function change the state of the repository on the filesystem
895
     *
896
     * @param string|TreeishInterface $ref    the reference to checkout
897
     * @param bool                    $create like -b on the command line
898
     *
899
     * @throws \RuntimeException
900
     * @throws \Symfony\Component\Process\Exception\LogicException
901
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
902 15
     * @throws \Symfony\Component\Process\Exception\RuntimeException
903
     * @return Repository
904 15
     */
905 9
    public function checkout($ref, $create = false)
906 9
    {
907 9
        if ($create && is_null($this->getBranch($ref))) {
0 ignored issues
show
Bug introduced by
It seems like $ref defined by parameter $ref on line 905 can also be of type object<GitElephant\Objects\TreeishInterface>; however, GitElephant\Repository::getBranch() 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...
908 9
            $this->createBranch($ref);
0 ignored issues
show
Bug introduced by
It seems like $ref defined by parameter $ref on line 905 can also be of type object<GitElephant\Objects\TreeishInterface>; however, GitElephant\Repository::createBranch() 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...
909 9
        }
910
        $this->caller->execute(MainCommand::getInstance($this)->checkout($ref));
0 ignored issues
show
Bug introduced by
It seems like $ref defined by parameter $ref on line 905 can also be of type object<GitElephant\Objects\TreeishInterface>; however, GitElephant\Command\MainCommand::checkout() does only seem to accept string|object<GitElephant\Objects\Branch>, 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...
911 15
912
	    $this->flushCache();
913
        return $this;
914
    }
915
916
    /**
917
     * Retrieve an instance of Tree
918
     * Tree Object is Countable, Iterable and has ArrayAccess for easy manipulation
919
     *
920
     * @param string|TreeishInterface $ref  the treeish to check
921
     * @param string|Object           $path Object or null for root
922
     *
923
     * @throws \RuntimeException
924
     * @throws \Symfony\Component\Process\Exception\LogicException
925 2
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
926
     * @throws \Symfony\Component\Process\Exception\RuntimeException
927 2
     * @return Objects\Tree
928
     */
929
    public function getTree($ref = 'HEAD', $path = null)
930
    {
931
        if (is_string($path) && '' !== $path) {
932
            $outputLines = $this->getCaller()->execute(
933
                LsTreeCommand::getInstance($this)->tree($ref, $path)
0 ignored issues
show
Bug introduced by
It seems like $ref defined by parameter $ref on line 929 can also be of type object<GitElephant\Objects\TreeishInterface>; however, GitElephant\Command\LsTreeCommand::tree() 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...
934
            )->getOutputLines(true);
935
            $path = TreeObject::createFromOutputLine($this, $outputLines[0]);
936
        }
937
938
        return new Tree($this, $ref, $path);
0 ignored issues
show
Bug introduced by
It seems like $ref defined by parameter $ref on line 929 can also be of type object<GitElephant\Objects\TreeishInterface>; however, GitElephant\Objects\Tree::__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...
Bug introduced by
It seems like $path defined by parameter $path on line 929 can also be of type string; however, GitElephant\Objects\Tree::__construct() does only seem to accept object|null, 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...
939
    }
940
941
    /**
942 2
     * Get a Diff object for a commit with its parent, by default the diff is between the current head and its parent
943
     *
944 2
     * @param \GitElephant\Objects\Commit|string      $commit1 A TreeishInterface instance
945
     * @param \GitElephant\Objects\Commit|string|null $commit2 A TreeishInterface instance
946 2
     * @param null|string|Object                      $path    The path to get the diff for or a Object instance
947
     *
948
     * @throws \RuntimeException
949
     * @throws \InvalidArgumentException
950
     * @return Objects\Diff\Diff
951
     */
952
    public function getDiff($commit1 = null, $commit2 = null, $path = null)
953
    {
954
        return Diff::create($this, $commit1, $commit2, $path);
0 ignored issues
show
Bug introduced by
It seems like $path defined by parameter $path on line 952 can also be of type object<GitElephant\Objects\Object>; however, GitElephant\Objects\Diff\Diff::create() does only seem to accept null|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...
955
    }
956
957
    /**
958
     * Clone a repository
959 7
     *
960
     * @param string $url the repository url (i.e. git://github.com/matteosister/GitElephant.git)
961 7
     * @param null   $to  where to clone the repo
962
     *
963 7
     * @throws \RuntimeException
964
     * @throws \Symfony\Component\Process\Exception\LogicException
965
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
966
     * @throws \Symfony\Component\Process\Exception\RuntimeException
967
     * @return Repository
968
     */
969
    public function cloneFrom($url, $to = null)
970
    {
971
        $this->caller->execute(CloneCommand::getInstance($this)->cloneUrl($url, $to));
972 1
973
        return $this;
974 1
    }
975
976
    /**
977
     * @param string $name remote name
978
     * @param string $url  remote url
979
     *
980
     * @throws \RuntimeException
981
     * @throws \Symfony\Component\Process\Exception\LogicException
982
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
983
     * @throws \Symfony\Component\Process\Exception\RuntimeException
984
     * @return Repository
985
     */
986
    public function addRemote($name, $url)
987
    {
988 1
        $this->caller->execute(RemoteCommand::getInstance($this)->add($name, $url));
989
990 1
        return $this;
991 1
    }
992 1
993 1
    /**
994 1
     * @param string $name         remote name
995 1
     * @param bool   $queryRemotes Fetch new information from remotes
996
     *
997 1
     * @return \GitElephant\Objects\Remote
998
     */
999
    public function getRemote($name, $queryRemotes = true)
1000
    {
1001
        return Remote::pick($this, $name, $queryRemotes);
1002
    }
1003
1004
    /**
1005
     * gets a list of remote objects
1006
     *
1007
     * @param bool $queryRemotes Fetch new information from remotes
1008
     *
1009
     * @throws \RuntimeException
1010
     * @throws \Symfony\Component\Process\Exception\LogicException
1011
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
1012 1
     * @throws \Symfony\Component\Process\Exception\RuntimeException
1013
     * @return array
1014 1
     */
1015 1
    public function getRemotes($queryRemotes = true)
1016 1
    {
1017 1
        $remoteNames = $this->caller->execute(RemoteCommand::getInstance($this)->show(null, $queryRemotes))
1018 1
          ->getOutputLines(true);
1019 1
        $remotes = array();
1020
        foreach ($remoteNames as $remoteName) {
1021
            $remotes[] = $this->getRemote($remoteName, $queryRemotes);
1022
        }
1023
1024
        return $remotes;
1025
    }
1026
1027
    /**
1028
     * Download objects and refs from another repository
1029
     *
1030
     * @param string $from
1031
     * @param string $ref
1032 2
     * @param array $args
1033
     * @param bool   $tags
1034 2
     *
1035 2
     * @throws \RuntimeException
1036
     * @throws \Symfony\Component\Process\Exception\LogicException
1037
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
1038
     * @throws \Symfony\Component\Process\Exception\RuntimeException
1039
     */
1040
    public function fetch($from = null, $ref = null, $args = [], $tags = false)
1041
    {
1042
        $options = array();
1043
        if ($tags === true) {
1044
            $options = array('--tags');
1045
        }
1046
1047 1
        if(is_array($args)) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after IF keyword; 0 found
Loading history...
1048
        	$options = array_merge($options, $args);
1049 1
        }
1050 1
1051
        $this->caller->execute(FetchCommand::getInstance($this)->fetch($from, $ref, $options));
1052
    }
1053
1054
    /**
1055
     * Fetch from and merge with another repository or a local branch
1056
     *
1057 2
     * @param string $from
1058
     * @param string $ref
1059 2
     * @param bool   $rebase
1060 2
     * @throws \RuntimeException
1061 2
     * @throws \Symfony\Component\Process\Exception\LogicException
1062
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
1063 2
     * @throws \Symfony\Component\Process\Exception\RuntimeException
1064
     */
1065
    public function pull($from = null, $ref = null, $rebase = true)
1066
    {
1067
        $this->caller->execute(PullCommand::getInstance($this)->pull($from, $ref, $rebase));
1068
    }
1069
1070
    /**
1071
     * Push changes to remote repository
1072
     *
1073
     * @param string $to
1074
     * @param string $ref
1075
     * @throws \RuntimeException
1076
     * @throws \Symfony\Component\Process\Exception\LogicException
1077
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
1078 1
     * @throws \Symfony\Component\Process\Exception\RuntimeException
1079
     */
1080 1
    public function push($to = null, $ref = null)
1081
    {
1082 1
        $this->caller->execute(PushCommand::getInstance($this)->push($to, $ref));
1083
    }
1084
1085
    /**
1086
     * get the humanish name of the repository
1087
     *
1088
     * @return string
1089
     */
1090
    public function getHumanishName()
1091
    {
1092
        $name = substr($this->getPath(), strrpos($this->getPath(), '/') + 1);
1093
        $name = str_replace('.git', '.', $name);
1094
        $name = str_replace('.bundle', '.', $name);
1095
1096
        return $name;
1097
    }
1098
1099
    /**
1100
     * output a node content as an array of lines
1101
     *
1102
     * @param \GitElephant\Objects\Object                  $obj     The Object of type BLOB
1103
     * @param \GitElephant\Objects\TreeishInterface|string $treeish A treeish object
1104
     *
1105
     * @throws \RuntimeException
1106
     * @throws \Symfony\Component\Process\Exception\LogicException
1107
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
1108
     * @throws \Symfony\Component\Process\Exception\RuntimeException
1109 61
     * @return array
1110
     */
1111 61
    public function outputContent(Object $obj, $treeish)
1112
    {
1113
        $command = CatFileCommand::getInstance($this)->content($obj, $treeish);
1114
1115
        return $this->caller->execute($command)->getOutputLines();
1116
    }
1117
1118
    /**
1119 1
     * output a node raw content
1120
     *
1121 1
     * @param \GitElephant\Objects\Object                  $obj     The Object of type BLOB
1122
     * @param \GitElephant\Objects\TreeishInterface|string $treeish A treeish object
1123
     *
1124
     * @throws \RuntimeException
1125
     * @throws \Symfony\Component\Process\Exception\LogicException
1126
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
1127
     * @throws \Symfony\Component\Process\Exception\RuntimeException
1128
     * @return string
1129 1
     */
1130
    public function outputRawContent(Object $obj, $treeish)
1131 1
    {
1132 1
        $command = CatFileCommand::getInstance($this)->content($obj, $treeish);
1133
1134
        return $this->caller->execute($command)->getRawOutput();
1135
    }
1136
1137
    /**
1138
     * Get the path
1139
     *
1140
     * @return string
1141
     */
1142
    public function getPath()
1143
    {
1144
        return $this->path;
1145
    }
1146
1147
    /**
1148
     * Get the repository name
1149 87
     *
1150
     * @return string
1151 87
     */
1152
    public function getName()
1153
    {
1154
        return $this->name;
1155
    }
1156
1157
    /**
1158
     * Set the repository name
1159 93
     *
1160
     * @param string $name the repository name
1161 93
     */
1162
    public function setName($name)
1163
    {
1164
        $this->name = $name;
1165
    }
1166
1167
    /**
1168
     * Caller setter
1169
     *
1170 1
     * @param \GitElephant\Command\Caller\Caller $caller the caller variable
1171
     */
1172 1
    public function setCaller($caller)
1173 1
    {
1174
        $this->caller = $caller;
1175
    }
1176
1177
    /**
1178
     * Caller getter
1179
     *
1180 1
     * @return \GitElephant\Command\Caller\Caller
1181
     */
1182 1
    public function getCaller()
1183 1
    {
1184 1
        return $this->caller;
1185 1
    }
1186
1187
    /**
1188
     * get global config list
1189
     *
1190
     * @return array Global config list
1191
     */
1192 93
    public function getGlobalConfigs()
1193
    {
1194 93
        return $this->globalConfigs;
1195
    }
1196
1197
    /**
1198
     * add a key/value pair to the global config list
1199
     *
1200
     * @param string $name  The config name
1201
     * @param string $value The config value
1202
     */
1203 1
    public function addGlobalConfig($name, $value)
1204
    {
1205 1
        $this->globalConfigs[$name] = $value;
1206 1
    }
1207
1208
    /**
1209
     * remove an element form the global config list, identified by key
1210
     *
1211
     * @param  string $name The config name
1212
     */
1213 1
    public function removeGlobalConfig($name)
1214
    {
1215 1
        if (isset($this->globalConfigs[$name])) {
1216 1
            unset($this->globalConfigs[$name]);
1217 1
        }
1218 1
    }
1219
1220
    /**
1221
     * get global options list
1222
     *
1223
     * @return array Global options list
1224
     */
1225 93
    public function getGlobalOptions()
1226
    {
1227 93
        return $this->globalOptions;
1228
    }
1229
1230
    /**
1231
     * add a key/value pair to the global option list
1232
     *
1233
     * @param string $name  The option name
1234
     * @param string $value The option value
1235 1
     */
1236
    public function addGlobalOption($name, $value)
1237 1
    {
1238 1
        $this->globalOptions[$name] = $value;
1239 1
    }
1240 1
1241
    /**
1242
     * remove an element form the global option list, identified by key
1243
     *
1244
     * @param  string $name The option name
1245
     */
1246
    public function removeGlobalOption($name)
1247
    {
1248 1
        if (isset($this->globalOptions[$name])) {
1249
            unset($this->globalOptions[$name]);
1250 1
        }
1251 1
    }
1252 1
1253 1
    /**
1254 1
     * get global command arguments list
1255
     *
1256
     * @return array Global command arguments list
1257
     */
1258
    public function getGlobalCommandArguments()
1259
    {
1260
        return $this->globalCommandArguments;
1261
    }
1262
1263
    /**
1264
     * add a value to the global command argument list
1265
     *
1266
     * @param string $value The command argument
1267
     */
1268
    public function addGlobalCommandArgument($value)
1269
    {
1270
        if (!in_array($value, $this->globalCommandArguments, true)) {
1271
            $this->globalCommandArguments[] = $value;
1272
        }
1273
    }
1274
1275
    /**
1276
     * remove an element form the global command argument list, identified by 
1277
     * value
1278
     *
1279
     * @param  string $value The command argument
1280
     */
1281
    public function removeGlobalCommandArgument($value)
1282
    {
1283
        if (in_array($value, $this->globalCommandArguments, true)) {
1284
            $index = array_search($value, $this->globalCommandArguments);
1285
            unset($this->globalCommandArguments[$index]);
1286
        }
1287
    }
1288
1289
	/**
1290
	 * Return the cache tag for this repository
1291
	 *
1292
	 * @return string
1293
	 */
1294
	private function getCacheTag() {
1295
1296
    	return 'repo_'.strtolower($this->getName());
1297
	}
1298
1299
	private function getCacheKey() {
1300
		$args = array_map('strtolower', debug_backtrace()[1]['args']);
1301
		return strtolower(debug_backtrace()[1]['function']).'_'.implode("", $args);
1302
	}
1303
1304
	/**
1305
	 * Flush the cache for this repository
1306
	 */
1307
    public function flushCache() {
1308
    	$cacheTag = $this->getCacheTag();
1309
    	Cache::tags($cacheTag)->flush();
1310
    }
1311
}
1312