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

Repository   F

Complexity

Total Complexity 103

Size/Duplication

Total Lines 1191
Duplicated Lines 0 %

Coupling/Cohesion

Components 4
Dependencies 33

Test Coverage

Coverage 90.94%

Importance

Changes 31
Bugs 5 Features 10
Metric Value
wmc 103
c 31
b 5
f 10
lcom 4
cbo 33
dl 0
loc 1191
ccs 291
cts 320
cp 0.9094
rs 0.5217

66 Methods

Rating   Name   Duplication   Size   Complexity  
A open() 0 4 1
A commit() 0 17 4
A __construct() 0 10 2
A stage() 0 6 1
A unstage() 0 6 1
A move() 0 6 1
A remove() 0 6 1
A revParse() 0 6 1
A isBare() 0 7 1
A createFromRemote() 0 17 3
A init() 0 6 1
A isClean() 0 4 1
A getPath() 0 4 1
A getName() 0 4 1
A getCaller() 0 4 1
A getGlobalCommandArguments() 0 4 1
A reset() 0 4 1
A getStatus() 0 4 1
A getWorkingTreeStatus() 0 4 1
A getIndexStatus() 0 4 1
A isDirty() 0 4 1
A getStatusOutput() 0 6 1
A createBranch() 0 6 1
A deleteBranch() 0 6 1
A getMainBranch() 0 12 1
A createTag() 0 6 1
A addSubmodule() 0 6 1
A initSubmodule() 0 5 1
A updateSubmodule() 0 5 1
A getLastTag() 0 17 2
A getCommit() 0 6 1
A countCommits() 0 6 1
A getObjectLog() 0 6 1
A getDiff() 0 4 1
A cloneFrom() 0 6 1
A addRemote() 0 6 1
A getRemote() 0 4 1
A pull() 0 4 1
A getHumanishName() 0 8 1
A outputContent() 0 6 1
A outputRawContent() 0 6 1
A setName() 0 4 1
A setCaller() 0 4 1
A getGlobalConfigs() 0 4 1
A addGlobalConfig() 0 4 1
A getGlobalOptions() 0 4 1
A addGlobalOption() 0 4 1
B getBranches() 0 24 3
A checkoutAllRemoteBranches() 0 20 4
B merge() 0 25 4
A deleteTag() 0 10 2
A getTags() 0 12 3
A getTag() 0 11 3
A getBranchOrTag() 0 14 4
A checkout() 0 9 3
A getTree() 0 11 3
A getRemotes() 0 11 2
A fetch() 0 8 2
A removeGlobalConfig() 0 6 2
A removeGlobalOption() 0 6 2
A addGlobalCommandArgument() 0 6 2
A removeGlobalCommandArgument() 0 7 2
A getLog() 0 4 1
A getLogRange() 0 14 3
A push() 0 4 1
A getBranch() 0 11 3

How to fix   Complexity   

Complex Class

Complex classes like Repository often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Repository, and based on these observations, apply Extract Interface, too.

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
57
/**
58
 * Repository
59
 *
60
 * Base Class for repository operations
61
 *
62
 * @author Matteo Giachino <[email protected]>
63
 * @author Dhaval Patel <[email protected]>
64
 */
65
class Repository
66
{
67
    /**
68
     * the repository path
69
     *
70
     * @var string
71
     */
72
    private $path;
73
74
    /**
75
     * the caller instance
76
     *
77
     * @var \GitElephant\Command\Caller\Caller
78
     */
79
    private $caller;
80
81
    /**
82
     * A general repository name
83
     *
84
     * @var string $name the repository name
85
     */
86
    private $name;
87
88
    /**
89
     * A list of global configs to apply to every command
90
     * 
91
     * @var array
92
     */
93
    private $globalConfigs = array();
94
95
    /**
96
     * A list of global options to apply to every command
97
     * 
98
     * @var array
99
     */
100
    private $globalOptions = array();
101
102
    /**
103
     * A list of global arguments to apply to every command
104
     * 
105
     * @var array
106
     */
107
    private $globalCommandArguments = array();
108
109
    /**
110
     * Class constructor
111
     *
112
     * @param string         $repositoryPath the path of the git repository
113
     * @param GitBinary|null $binary         the GitBinary instance that calls the commands
114
     * @param string         $name           a repository name
115
     *
116
     * @throws Exception\InvalidRepositoryPathException
117
     */
118 103
    public function __construct($repositoryPath, GitBinary $binary = null, $name = null)
119
    {
120 103
        if (is_null($binary)) {
121 103
            $binary = new GitBinary();
122 103
        }
123
124 103
        $this->path = $repositoryPath;
125 103
        $this->caller = new Caller($binary, $repositoryPath);
126 103
        $this->name = $name;
127 103
    }
128
129
    /**
130
     * Factory method
131
     *
132
     * @param string         $repositoryPath the path of the git repository
133
     * @param GitBinary|null $binary         the GitBinary instance that calls the commands
134
     * @param string         $name           a repository name
135
     *
136
     * @return \GitElephant\Repository
137
     */
138 102
    public static function open($repositoryPath, GitBinary $binary = null, $name = null)
139 1
    {
140 102
        return new self($repositoryPath, $binary, $name);
141
    }
142
143
    /**
144
     * create a repository from a remote git url, or a local filesystem
145
     * and save it in a temp folder
146
     *
147
     * @param string|Repository $git            the git remote url, or the filesystem path
148
     * @param null              $repositoryPath path
149
     * @param GitBinary         $binary         binary
150
     * @param null              $name           repository name
151
     *
152
     * @throws \RuntimeException
153
     * @throws \Symfony\Component\Filesystem\Exception\IOException
154
     * @return Repository
155
     */
156 1
    public static function createFromRemote($git, $repositoryPath = null, GitBinary $binary = null, $name = null)
157
    {
158 1
        if (null === $repositoryPath) {
159 1
            $tempDir = realpath(sys_get_temp_dir());
160 1
            $repositoryPath = sprintf('%s%s%s', $tempDir, DIRECTORY_SEPARATOR, sha1(uniqid()));
161 1
            $fs = new Filesystem();
162 1
            $fs->mkdir($repositoryPath);
163 1
        }
164 1
        $repository = new Repository($repositoryPath, $binary, $name);
165 1
        if ($git instanceof Repository) {
166
            $git = $git->getPath();
167
        }
168 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 160 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...
169 1
        $repository->checkoutAllRemoteBranches();
170
171 1
        return $repository;
172
    }
173
174
    /**
175
     * Init the repository
176
     *
177
     * @param bool $bare created a bare repository
178
     *
179
     * @throws \RuntimeException
180
     * @throws \Symfony\Component\Process\Exception\LogicException
181
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
182
     * @throws \Symfony\Component\Process\Exception\RuntimeException
183
     * @return Repository
184
     */
185 92
    public function init($bare = false)
186
    {
187 92
        $this->caller->execute(MainCommand::getInstance($this)->init($bare));
188
189 92
        return $this;
190
    }
191
192
    /**
193
     * Stage the working tree content
194
     *
195
     * @param string|Object $path the path to store
196
     *
197
     * @throws \RuntimeException
198
     * @throws \Symfony\Component\Process\Exception\LogicException
199
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
200
     * @throws \Symfony\Component\Process\Exception\RuntimeException
201
     * @return Repository
202
     */
203 88
    public function stage($path = '.')
204
    {
205 88
        $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 203 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...
206
207 88
        return $this;
208
    }
209
210
    /**
211
     * Unstage a tree content
212
     *
213
     * @param string|Object $path the path to unstage
214
     *
215
     * @throws \RuntimeException
216
     * @throws \Symfony\Component\Process\Exception\LogicException
217
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
218
     * @throws \Symfony\Component\Process\Exception\RuntimeException
219
     * @return Repository
220
     */
221 2
    public function unstage($path)
222
    {
223 2
        $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 221 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...
224
225 2
        return $this;
226
    }
227
228
    /**
229
     * Move a file/directory
230
     *
231
     * @param string|Object $from source path
232
     * @param string|Object $to   destination path
233
     *
234
     * @throws \RuntimeException
235
     * @throws \Symfony\Component\Process\Exception\LogicException
236
     * @throws \InvalidArgumentException
237
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
238
     * @throws \Symfony\Component\Process\Exception\RuntimeException
239
     * @return Repository
240
     */
241 1
    public function move($from, $to)
242
    {
243 1
        $this->caller->execute(MainCommand::getInstance($this)->move($from, $to));
244
245 1
        return $this;
246
    }
247
248
    /**
249
     * Remove a file/directory
250
     *
251
     * @param string|Object $path      the path to remove
252
     * @param bool          $recursive recurse
253
     * @param bool          $force     force
254
     *
255
     * @throws \RuntimeException
256
     * @throws \Symfony\Component\Process\Exception\LogicException
257
     * @throws \InvalidArgumentException
258
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
259
     * @throws \Symfony\Component\Process\Exception\RuntimeException
260
     * @return Repository
261
     */
262 1
    public function remove($path, $recursive = false, $force = false)
263
    {
264 1
        $this->caller->execute(MainCommand::getInstance($this)->remove($path, $recursive, $force));
265
266 1
        return $this;
267
    }
268
269
    /**
270
     * Commit content to the repository, eventually staging all unstaged content
271
     *
272
     * @param string        $message  the commit message
273
     * @param bool          $stageAll whether to stage on not everything before commit
274
     * @param string|null   $ref      the reference to commit to (checkout -> commit -> checkout previous)
275
     * @param string|Author $author   override the author for this commit
276
     *
277
     * @throws \RuntimeException
278
     * @throws \InvalidArgumentException
279
     * @throws \Symfony\Component\Process\Exception\RuntimeException
280
     * @return Repository
281
     */
282 85
    public function commit($message, $stageAll = false, $ref = null, $author = null, $allowEmpty = false)
283
    {
284 85
        $currentBranch = null;
285 85
        if (! is_null($ref)) {
286 1
            $currentBranch = $this->getMainBranch();
287 1
            $this->checkout($ref);
288 1
        }
289 85
        if ($stageAll) {
290 83
            $this->stage();
291 83
        }
292 85
        $this->caller->execute(MainCommand::getInstance($this)->commit($message, $stageAll, $author, $allowEmpty));
293 85
        if (! is_null($ref)) {
294 1
            $this->checkout($currentBranch);
0 ignored issues
show
Bug introduced by
It seems like $currentBranch defined by null on line 284 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...
295 1
        }
296
297 85
        return $this;
298
    }
299
300
    /**
301
     * rev-parse command - often used to return a commit tag.
302
     *
303
     * @param array                  $options the options to apply to rev-parse
304
     * @param string|Object|Commit   $arg the argument (may be a branch head, etc)
305
     *
306
     * @throws \RuntimeException
307
     * @throws \InvalidArgumentException
308
     * @throws \Symfony\Component\Process\Exception\RuntimeException
309
     * @return array
310
     */
311 1
    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...
312
    {
313 1
        $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 311 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...
314
315 1
        return array_map('trim', $this->caller->getOutputLines(true));
316
    }
317
318
    /**
319
     * Check if this is a bare repository
320
     * @return boolean
321
     */
322 1
    public function isBare()
323
    {
324 1
        $options = array(RevParseCommand::OPTION_IS_BARE_REPOSIORY);
325 1
        $this->caller->execute(RevParseCommand::getInstance()->revParse(null, $options));
326
327 1
        return trim($this->caller->getOutput()) === 'true';
328
    }
329
330
    /**
331
     * @param TreeishInterface|Commit|string $arg
332
     * @param array $options
333
     */
334 2
    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...
335
    {
336 2
        $this->caller->execute(ResetCommand::getInstance($this)->reset($arg,$options));
337 2
    }
338
339
    /**
340
     * Get the repository status
341
     *
342
     * @return Status
343
     */
344 5
    public function getStatus()
345
    {
346 5
        return Status::get($this);
347
    }
348
349
    /**
350
     * @return StatusWorkingTree
351
     */
352 1
    public function getWorkingTreeStatus()
353
    {
354 1
        return StatusWorkingTree::get($this);
355
    }
356
357
    /**
358
     * @return StatusIndex
359
     */
360 4
    public function getIndexStatus()
361
    {
362 4
        return StatusIndex::get($this);
363
    }
364
    
365
    /**
366
     * isClean Return true if the repository is not dirty.
367
     * 
368
     * @return boolean
369
     */
370
    public function isClean()
371
    {
372
        return $this->getStatus()->all()->isEmpty();
373
    }
374
    
375
    /**
376
     * isDirty Return true if the repository has some modified files.
377
     * 
378
     * @return boolean
379
     */
380
    public function isDirty()
381
    {
382
        return !$this->isClean();
383
    }
384
385
    /**
386
     * Get the repository status as a string
387
     *
388
     * @throws \RuntimeException
389
     * @throws \Symfony\Component\Process\Exception\LogicException
390
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
391
     * @throws \Symfony\Component\Process\Exception\RuntimeException
392
     * @return array
393
     */
394 4
    public function getStatusOutput()
395
    {
396 4
        $this->caller->execute(MainCommand::getInstance($this)->status());
397
398 4
        return array_map('trim', $this->caller->getOutputLines());
399
    }
400
401
    /**
402
     * Create a new branch
403
     *
404
     * @param string $name       the new branch name
405
     * @param null   $startPoint the reference to create the branch from
406
     *
407
     * @throws \RuntimeException
408
     * @throws \Symfony\Component\Process\Exception\RuntimeException
409
     * @return Repository
410
     */
411 27
    public function createBranch($name, $startPoint = null)
412
    {
413 27
        Branch::create($this, $name, $startPoint);
414
415 27
        return $this;
416
    }
417
418
    /**
419
     * Delete a branch by its name
420
     * This function change the state of the repository on the filesystem
421
     *
422
     * @param string $name  The branch to delete
423
     * @param bool   $force Force the delete
424
     *
425
     * @throws \RuntimeException
426
     * @throws \Symfony\Component\Process\Exception\LogicException
427
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
428
     * @throws \Symfony\Component\Process\Exception\RuntimeException
429
     * @return Repository
430
     */
431 1
    public function deleteBranch($name, $force = false)
432
    {
433 1
        $this->caller->execute(BranchCommand::getInstance($this)->delete($name, $force));
434
435 1
        return $this;
436
    }
437
438
    /**
439
     * An array of Branch objects
440
     *
441
     * @param bool $namesOnly return an array of branch names as a string
442
     * @param bool $all       lists also remote branches
443
     *
444
     * @throws \RuntimeException
445
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
446
     * @throws \Symfony\Component\Process\Exception\LogicException
447
     * @throws \InvalidArgumentException
448
     * @throws \Symfony\Component\Process\Exception\RuntimeException
449
     * @return array
450
     */
451 17
    public function getBranches($namesOnly = false, $all = false)
452
    {
453 17
        $branches = array();
454 17
        if ($namesOnly) {
455 6
            $outputLines = $this->caller->execute(
456 6
                BranchCommand::getInstance($this)->listBranches($all, true)
457 6
            )->getOutputLines(true);
458 6
            $branches = array_map(
459
                function ($v) {
460 6
                    return ltrim($v, '* ');
461 6
                },
462
                $outputLines
463 6
            );
464 6
        } else {
465 14
            $outputLines = $this->caller->execute(
466 14
                BranchCommand::getInstance($this)->listBranches($all)
467 14
            )->getOutputLines(true);
468 14
            foreach ($outputLines as $branchLine) {
469 14
                $branches[] = Branch::createFromOutputLine($this, $branchLine);
470 14
            }
471
        }
472
473 17
        return $branches;
474
    }
475
476
    /**
477
     * Return the actually checked out branch
478
     *
479
     * @throws \RuntimeException
480
     * @throws \InvalidArgumentException
481
     * @throws \Symfony\Component\Process\Exception\RuntimeException
482
     * @return Objects\Branch
483
     */
484 5
    public function getMainBranch()
485
    {
486 5
        $filtered = array_filter(
487 5
            $this->getBranches(),
488
            function (Branch $branch) {
489 5
                return $branch->getCurrent();
490
            }
491 5
        );
492 5
        sort($filtered);
493
494 5
        return $filtered[0];
495
    }
496
497
    /**
498
     * Retrieve a Branch object by a branch name
499
     *
500
     * @param string $name The branch name
501
     *
502
     * @throws \RuntimeException
503
     * @throws \InvalidArgumentException
504
     * @throws \Symfony\Component\Process\Exception\RuntimeException
505
     * @return null|Branch
506
     */
507 9
    public function getBranch($name)
508
    {
509
        /** @var Branch $branch */
510 9
        foreach ($this->getBranches() as $branch) {
511 9
            if ($branch->getName() == $name) {
512 9
                return $branch;
513
            }
514 4
        }
515
516 1
        return null;
517
    }
518
519
    /**
520
     * Checkout all branches from the remote and make them local
521
     *
522
     * @param string $remote remote to fetch from
523
     *
524
     * @throws \RuntimeException
525
     * @throws \InvalidArgumentException
526
     * @throws \Symfony\Component\Process\Exception\RuntimeException
527
     * @return Repository
528
     */
529 1
    public function checkoutAllRemoteBranches($remote = 'origin')
530
    {
531 1
        $actualBranch = $this->getMainBranch();
532 1
        $actualBranches = $this->getBranches(true, false);
533 1
        $allBranches = $this->getBranches(true, true);
534 1
        $realBranches = array_filter(
535 1
            $allBranches,
536 1
            function ($branch) use ($actualBranches) {
537 1
                return !in_array($branch, $actualBranches)
538 1
                && preg_match('/^remotes(.+)$/', $branch)
539 1
                && !preg_match('/^(.+)(HEAD)(.*?)$/', $branch);
540
            }
541 1
        );
542 1
        foreach ($realBranches as $realBranch) {
543 1
            $this->checkout(str_replace(sprintf('remotes/%s/', $remote), '', $realBranch));
544 1
        }
545 1
        $this->checkout($actualBranch);
546
547 1
        return $this;
548
    }
549
550
    /**
551
     * Merge a Branch in the current checked out branch
552
     *
553
     * @param Objects\Branch $branch  The branch to merge in the current checked out branch
554
     * @param string         $message The message for the merge commit, if merge is 3-way
555
     * @param string         $mode    The merge mode: ff-only, no-ff or auto
556
     *
557
     * @throws \RuntimeException
558
     * @throws \Symfony\Component\Process\Exception\LogicException
559
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
560
     * @throws \Symfony\Component\Process\Exception\RuntimeException
561
     * @return Repository
562
     */
563 2
    public function merge(Branch $branch, $message = '', $mode = 'auto')
564
    {
565
        $valid_modes = array(
566 2
            'auto',    // deafult git behavior
567 2
            'ff-only', // force fast forward merge
568 2
            'no-ff',   // force 3-way merge
569 2
        );
570 2
        if (!in_array($mode, $valid_modes)) {
571
            throw new \Symfony\Component\Process\Exception\InvalidArgumentException("Invalid merge mode: $mode.");
572
        }
573
574 2
        $options = array();
575
        switch ($mode) {
576 2
            case 'ff-only':
577 1
                $options[] = MergeCommand::MERGE_OPTION_FF_ONLY;
578 1
                break;
579 2
            case 'no-ff':
580 2
                $options[] = MergeCommand::MERGE_OPTION_NO_FF;
581 1
                break;
582
        }
583
584 2
        $this->caller->execute(MergeCommand::getInstance($this)->merge($branch, $message, $options));
585
586 2
        return $this;
587
    }
588
589
    /**
590
     * Create a new tag
591
     * This function change the state of the repository on the filesystem
592
     *
593
     * @param string $name       The new tag name
594
     * @param null   $startPoint The reference to create the tag from
595
     * @param null   $message    the tag message
596
     *
597
     * @throws \RuntimeException
598
     * @throws \Symfony\Component\Process\Exception\RuntimeException
599
     * @return Repository
600
     */
601 25
    public function createTag($name, $startPoint = null, $message = null)
602
    {
603 25
        Tag::create($this, $name, $startPoint, $message);
604
605 25
        return $this;
606
    }
607
608
    /**
609
     * Delete a tag by it's name or by passing a Tag object
610
     * This function change the state of the repository on the filesystem
611
     *
612
     * @param string|Tag $tag The tag name or the Tag object
613
     *
614
     * @throws \RuntimeException
615
     * @throws \Symfony\Component\Process\Exception\RuntimeException
616
     * @return Repository
617
     */
618 2
    public function deleteTag($tag)
619
    {
620 2
        if ($tag instanceof Tag) {
621 1
            $tag->delete();
622 1
        } else {
623 1
            Tag::pick($this, $tag)->delete();
624
        }
625
626 2
        return $this;
627
    }
628
629
    /**
630
     * add a git submodule to the repository
631
     *
632
     * @param string $gitUrl git url of the submodule
633
     * @param string $path   path to register the submodule to
634
     *
635
     * @throws \RuntimeException
636
     * @throws \Symfony\Component\Process\Exception\LogicException
637
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
638
     * @throws \Symfony\Component\Process\Exception\RuntimeException
639
     * @return Repository
640
     */
641 1
    public function addSubmodule($gitUrl, $path = null)
642
    {
643 1
        $this->caller->execute(SubmoduleCommand::getInstance($this)->add($gitUrl, $path));
644
645 1
        return $this;
646
    }
647
648
    /**
649
     * initialize submodules
650
     *
651
     * @param  string $path init only submodules at the specified path
652
     *
653
     * @return Repository
654
     */
655
    public function initSubmodule($path = null)
656
    {
657
        $this->caller->execute(SubmoduleCommand::getInstance($this)->init($path));
658
        return $this;
659
    }
660
661
    /**
662
     * update submodules
663
     *
664
     * @param  bool   $recursive update recursively
665
     * @param  bool   $init      init before update
666
     * @param  bool   $force     force the checkout as part of update
667
     * @param  string $path      update only a specific submodule path
668
     *
669
     * @return Repository
670
     */
671
    public function updateSubmodule($recursive = false, $init = false, $force = false, $path = null)
672
    {
673
        $this->caller->execute(SubmoduleCommand::getInstance($this)->update($recursive, $init, $force, $path));
674
        return $this;
675
    }
676
677
    /**
678
     * Gets an array of Tag objects
679
     *
680
     * @throws \RuntimeException
681
     * @throws \Symfony\Component\Process\Exception\LogicException
682
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
683
     * @throws \Symfony\Component\Process\Exception\RuntimeException
684
     * @return array
685
     */
686 2
    public function getTags()
687
    {
688 2
        $tags = array();
689 2
        $this->caller->execute(TagCommand::getInstance($this)->listTags());
690 2
        foreach ($this->caller->getOutputLines() as $tagString) {
691 2
            if ($tagString != '') {
692 2
                $tags[] = new Tag($this, trim($tagString));
693 2
            }
694 2
        }
695
696 2
        return $tags;
697
    }
698
699
    /**
700
     * Return a tag object
701
     *
702
     * @param string $name The tag name
703
     *
704
     * @throws \RuntimeException
705
     * @throws \Symfony\Component\Process\Exception\RuntimeException
706
     * @return Tag|null
707
     */
708 27
    public function getTag($name)
709
    {
710 27
        $tagFinderOutput = $this->caller->execute(TagCommand::getInstance()->listTags())->getOutputLines(true);
711 27
        foreach ($tagFinderOutput as $line) {
712 27
            if ($line === $name) {
713 27
                return new Tag($this, $name);
714
            }
715 5
        }
716
717 1
        return null;
718
    }
719
720
    /**
721
     * Return the last created tag
722
     *
723
     * @throws \LogicException
724
     * @throws \RuntimeException
725
     * @throws \InvalidArgumentException
726
     * @return Tag|null
727
     */
728 1
    public function getLastTag()
729
    {
730 1
        $finder = Finder::create()
731 1
                  ->files()
732 1
                  ->in(sprintf('%s/.git/refs/tags', $this->path))
733 1
                  ->sortByChangedTime();
734 1
        if ($finder->count() == 0) {
735
            return null;
736
        }
737 1
        $files = iterator_to_array($finder->getIterator(), false);
738 1
        $files = array_reverse($files);
739
        /** @var $firstFile SplFileInfo */
740 1
        $firstFile = $files[0];
741 1
        $tagName = $firstFile->getFilename();
742
743 1
        return Tag::pick($this, $tagName);
744
    }
745
746
    /**
747
     * Try to get a branch or a tag by its name.
748
     *
749
     * @param string $name the reference name (a tag name or a branch name)
750
     *
751
     * @throws \RuntimeException
752
     * @throws \InvalidArgumentException
753
     * @throws \Symfony\Component\Process\Exception\RuntimeException
754
     * @return \GitElephant\Objects\Tag|\GitElephant\Objects\Branch|null
755
     */
756 1
    public function getBranchOrTag($name)
757
    {
758 1
        if (in_array($name, $this->getBranches(true))) {
759 1
            return new Branch($this, $name);
760
        }
761 1
        $tagFinderOutput = $this->caller->execute(TagCommand::getInstance($this)->listTags())->getOutputLines(true);
762 1
        foreach ($tagFinderOutput as $line) {
763 1
            if ($line === $name) {
764 1
                return new Tag($this, $name);
765
            }
766 1
        }
767
768 1
        return null;
769
    }
770
771
    /**
772
     * Return a Commit object
773
     *
774
     * @param string $ref The commit reference
775
     *
776
     * @throws \RuntimeException
777
     * @return Objects\Commit
778
     */
779 13
    public function getCommit($ref = 'HEAD')
780
    {
781 13
        $commit = Commit::pick($this, $ref);
782
783 13
        return $commit;
784
    }
785
786
    /**
787
     * count the commit to arrive to the given treeish
788
     *
789
     * @param string $start
790
     *
791
     * @throws \RuntimeException
792
     * @throws \Symfony\Component\Process\Exception\RuntimeException
793
     * @return int|void
794
     */
795 3
    public function countCommits($start = 'HEAD')
796
    {
797 3
        $commit = Commit::pick($this, $start);
798
799 3
        return $commit->count();
800
    }
801
802
    /**
803
     * Get a log for a ref
804
     *
805
     * @param string|TreeishInterface|array $ref         the treeish to check, as a string, as an object or as an array
806
     * @param string|Object                 $path        the physical path to the tree relative to the repository root
807
     * @param int|null                      $limit       limit to n entries
808
     * @param int|null                      $offset      skip n entries
809
     * @param boolean|false                 $firstParent skip commits brought in to branch by a merge
810
     *
811
     * @return \GitElephant\Objects\Log
812
     */
813 20
    public function getLog($ref = 'HEAD', $path = null, $limit = 10, $offset = null, $firstParent = false)
814
    {
815 20
        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 813 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 813 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...
816
    }
817
818
    /**
819
     * Get a log for a range ref
820
     *
821
     * @param string        $refStart
822
     * @param string        $refEnd
823
     * @param string|Object $path        the physical path to the tree relative to the repository root
824
     * @param int|null      $limit       limit to n entries
825
     * @param int|null      $offset      skip n entries
826
     * @param boolean|false $firstParent skip commits brought in to branch by a merge
827
     *
828
     * @return \GitElephant\Objects\LogRange
829
     */
830
    public function getLogRange($refStart, $refEnd, $path = null, $limit = 10, $offset = null, $firstParent = false)
831
    {
832
        // Handle when clients provide bad start reference on branch creation
833
        if (preg_match('~^[0]+$~', $refStart)) {
834
            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 830 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 830 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...
835
        }
836
837
        // Handle when clients provide bad end reference on branch deletion
838
        if (preg_match('~^[0]+$~', $refEnd)) {
839
            $refEnd = $refStart;
840
        }
841
842
        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 830 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 830 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...
843
    }
844
845
    /**
846
     * Get a log for an object
847
     *
848
     * @param \GitElephant\Objects\Object             $obj    The Object instance
849
     * @param null|string|\GitElephant\Objects\Branch $branch The branch to read from
850
     * @param int                                     $limit  Limit to n entries
851
     * @param int|null                                $offset Skip n entries
852
     *
853
     * @throws \RuntimeException
854
     * @throws \Symfony\Component\Process\Exception\LogicException
855
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
856
     * @throws \Symfony\Component\Process\Exception\RuntimeException
857
     * @return \GitElephant\Objects\Log
858
     */
859 3
    public function getObjectLog(Object $obj, $branch = null, $limit = 1, $offset = null)
860
    {
861 3
        $command = LogCommand::getInstance($this)->showObjectLog($obj, $branch, $limit, $offset);
862
863 3
        return Log::createFromOutputLines($this, $this->caller->execute($command)->getOutputLines());
864
    }
865
866
    /**
867
     * Checkout a branch
868
     * This function change the state of the repository on the filesystem
869
     *
870
     * @param string|TreeishInterface $ref    the reference to checkout
871
     * @param bool                    $create like -b on the command line
872
     *
873
     * @throws \RuntimeException
874
     * @throws \Symfony\Component\Process\Exception\LogicException
875
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
876
     * @throws \Symfony\Component\Process\Exception\RuntimeException
877
     * @return Repository
878
     */
879 24
    public function checkout($ref, $create = false)
880
    {
881 24
        if ($create && is_null($this->getBranch($ref))) {
0 ignored issues
show
Bug introduced by
It seems like $ref defined by parameter $ref on line 879 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...
882
            $this->createBranch($ref);
0 ignored issues
show
Bug introduced by
It seems like $ref defined by parameter $ref on line 879 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...
883
        }
884 24
        $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 879 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...
885
886 24
        return $this;
887
    }
888
889
    /**
890
     * Retrieve an instance of Tree
891
     * Tree Object is Countable, Iterable and has ArrayAccess for easy manipulation
892
     *
893
     * @param string|TreeishInterface $ref  the treeish to check
894
     * @param string|Object           $path Object or null for root
895
     *
896
     * @throws \RuntimeException
897
     * @throws \Symfony\Component\Process\Exception\LogicException
898
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
899
     * @throws \Symfony\Component\Process\Exception\RuntimeException
900
     * @return Objects\Tree
901
     */
902 15
    public function getTree($ref = 'HEAD', $path = null)
903
    {
904 15
        if (is_string($path) && '' !== $path) {
905 9
            $outputLines = $this->getCaller()->execute(
906 9
                LsTreeCommand::getInstance($this)->tree($ref, $path)
0 ignored issues
show
Bug introduced by
It seems like $ref defined by parameter $ref on line 902 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...
907 9
            )->getOutputLines(true);
908 9
            $path = TreeObject::createFromOutputLine($this, $outputLines[0]);
909 9
        }
910
911 15
        return new Tree($this, $ref, $path);
0 ignored issues
show
Bug introduced by
It seems like $ref defined by parameter $ref on line 902 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 902 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...
912
    }
913
914
    /**
915
     * Get a Diff object for a commit with its parent, by default the diff is between the current head and its parent
916
     *
917
     * @param \GitElephant\Objects\Commit|string      $commit1 A TreeishInterface instance
918
     * @param \GitElephant\Objects\Commit|string|null $commit2 A TreeishInterface instance
919
     * @param null|string|Object                      $path    The path to get the diff for or a Object instance
920
     *
921
     * @throws \RuntimeException
922
     * @throws \InvalidArgumentException
923
     * @return Objects\Diff\Diff
924
     */
925 2
    public function getDiff($commit1 = null, $commit2 = null, $path = null)
926
    {
927 2
        return Diff::create($this, $commit1, $commit2, $path);
0 ignored issues
show
Bug introduced by
It seems like $path defined by parameter $path on line 925 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...
928
    }
929
930
    /**
931
     * Clone a repository
932
     *
933
     * @param string $url the repository url (i.e. git://github.com/matteosister/GitElephant.git)
934
     * @param null   $to  where to clone the repo
935
     *
936
     * @throws \RuntimeException
937
     * @throws \Symfony\Component\Process\Exception\LogicException
938
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
939
     * @throws \Symfony\Component\Process\Exception\RuntimeException
940
     * @return Repository
941
     */
942 2
    public function cloneFrom($url, $to = null)
943
    {
944 2
        $this->caller->execute(CloneCommand::getInstance($this)->cloneUrl($url, $to));
945
946 2
        return $this;
947
    }
948
949
    /**
950
     * @param string $name remote name
951
     * @param string $url  remote url
952
     *
953
     * @throws \RuntimeException
954
     * @throws \Symfony\Component\Process\Exception\LogicException
955
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
956
     * @throws \Symfony\Component\Process\Exception\RuntimeException
957
     * @return Repository
958
     */
959 7
    public function addRemote($name, $url)
960
    {
961 7
        $this->caller->execute(RemoteCommand::getInstance($this)->add($name, $url));
962
963 7
        return $this;
964
    }
965
966
    /**
967
     * @param string $name         remote name
968
     * @param bool   $queryRemotes Fetch new information from remotes
969
     *
970
     * @return \GitElephant\Objects\Remote
971
     */
972 1
    public function getRemote($name, $queryRemotes = true)
973
    {
974 1
        return Remote::pick($this, $name, $queryRemotes);
975
    }
976
977
    /**
978
     * gets a list of remote objects
979
     *
980
     * @param bool $queryRemotes Fetch new information from remotes
981
     *
982
     * @throws \RuntimeException
983
     * @throws \Symfony\Component\Process\Exception\LogicException
984
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
985
     * @throws \Symfony\Component\Process\Exception\RuntimeException
986
     * @return array
987
     */
988 1
    public function getRemotes($queryRemotes = true)
989
    {
990 1
        $remoteNames = $this->caller->execute(RemoteCommand::getInstance($this)->show(null, $queryRemotes))
991 1
          ->getOutputLines(true);
992 1
        $remotes = array();
993 1
        foreach ($remoteNames as $remoteName) {
994 1
            $remotes[] = $this->getRemote($remoteName, $queryRemotes);
995 1
        }
996
997 1
        return $remotes;
998
    }
999
1000
    /**
1001
     * Download objects and refs from another repository
1002
     *
1003
     * @param string $from
1004
     * @param string $ref
1005
     * @param bool   $tags
1006
     *
1007
     * @throws \RuntimeException
1008
     * @throws \Symfony\Component\Process\Exception\LogicException
1009
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
1010
     * @throws \Symfony\Component\Process\Exception\RuntimeException
1011
     */
1012 1
    public function fetch($from = null, $ref = null, $tags = false)
1013
    {
1014 1
        $options = array();
1015 1
        if ($tags === true) {
1016 1
            $options = array('--tags');
1017 1
        }
1018 1
        $this->caller->execute(FetchCommand::getInstance($this)->fetch($from, $ref, $options));
1019 1
    }
1020
1021
    /**
1022
     * Fetch from and merge with another repository or a local branch
1023
     *
1024
     * @param string $from
1025
     * @param string $ref
1026
     * @param bool   $rebase
1027
     * @throws \RuntimeException
1028
     * @throws \Symfony\Component\Process\Exception\LogicException
1029
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
1030
     * @throws \Symfony\Component\Process\Exception\RuntimeException
1031
     */
1032 2
    public function pull($from = null, $ref = null, $rebase = true)
1033
    {
1034 2
        $this->caller->execute(PullCommand::getInstance($this)->pull($from, $ref, $rebase));
1035 2
    }
1036
1037
    /**
1038
     * Push changes to remote repository
1039
     *
1040
     * @param string $to
1041
     * @param string $ref
1042
     * @throws \RuntimeException
1043
     * @throws \Symfony\Component\Process\Exception\LogicException
1044
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
1045
     * @throws \Symfony\Component\Process\Exception\RuntimeException
1046
     */
1047 1
    public function push($to = null, $ref = null)
1048
    {
1049 1
        $this->caller->execute(PushCommand::getInstance($this)->push($to, $ref));
1050 1
    }
1051
1052
    /**
1053
     * get the humanish name of the repository
1054
     *
1055
     * @return string
1056
     */
1057 2
    public function getHumanishName()
1058
    {
1059 2
        $name = substr($this->getPath(), strrpos($this->getPath(), '/') + 1);
1060 2
        $name = str_replace('.git', '.', $name);
1061 2
        $name = str_replace('.bundle', '.', $name);
1062
1063 2
        return $name;
1064
    }
1065
1066
    /**
1067
     * output a node content as an array of lines
1068
     *
1069
     * @param \GitElephant\Objects\Object                  $obj     The Object of type BLOB
1070
     * @param \GitElephant\Objects\TreeishInterface|string $treeish A treeish object
1071
     *
1072
     * @throws \RuntimeException
1073
     * @throws \Symfony\Component\Process\Exception\LogicException
1074
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
1075
     * @throws \Symfony\Component\Process\Exception\RuntimeException
1076
     * @return array
1077
     */
1078 1
    public function outputContent(Object $obj, $treeish)
1079
    {
1080 1
        $command = CatFileCommand::getInstance($this)->content($obj, $treeish);
1081
1082 1
        return $this->caller->execute($command)->getOutputLines();
1083
    }
1084
1085
    /**
1086
     * output a node raw content
1087
     *
1088
     * @param \GitElephant\Objects\Object                  $obj     The Object of type BLOB
1089
     * @param \GitElephant\Objects\TreeishInterface|string $treeish A treeish object
1090
     *
1091
     * @throws \RuntimeException
1092
     * @throws \Symfony\Component\Process\Exception\LogicException
1093
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
1094
     * @throws \Symfony\Component\Process\Exception\RuntimeException
1095
     * @return string
1096
     */
1097
    public function outputRawContent(Object $obj, $treeish)
1098
    {
1099
        $command = CatFileCommand::getInstance($this)->content($obj, $treeish);
1100
1101
        return $this->caller->execute($command)->getRawOutput();
1102
    }
1103
1104
    /**
1105
     * Get the path
1106
     *
1107
     * @return string
1108
     */
1109 61
    public function getPath()
1110
    {
1111 61
        return $this->path;
1112
    }
1113
1114
    /**
1115
     * Get the repository name
1116
     *
1117
     * @return string
1118
     */
1119 1
    public function getName()
1120
    {
1121 1
        return $this->name;
1122
    }
1123
1124
    /**
1125
     * Set the repository name
1126
     *
1127
     * @param string $name the repository name
1128
     */
1129 1
    public function setName($name)
1130
    {
1131 1
        $this->name = $name;
1132 1
    }
1133
1134
    /**
1135
     * Caller setter
1136
     *
1137
     * @param \GitElephant\Command\Caller\Caller $caller the caller variable
1138
     */
1139
    public function setCaller($caller)
1140
    {
1141
        $this->caller = $caller;
1142
    }
1143
1144
    /**
1145
     * Caller getter
1146
     *
1147
     * @return \GitElephant\Command\Caller\Caller
1148
     */
1149 87
    public function getCaller()
1150
    {
1151 87
        return $this->caller;
1152
    }
1153
1154
    /**
1155
     * get global config list
1156
     *
1157
     * @return array Global config list
1158
     */
1159 93
    public function getGlobalConfigs()
1160
    {
1161 93
        return $this->globalConfigs;
1162
    }
1163
1164
    /**
1165
     * add a key/value pair to the global config list
1166
     *
1167
     * @param string $name  The config name
1168
     * @param string $value The config value
1169
     */
1170 1
    public function addGlobalConfig($name, $value)
1171
    {
1172 1
        $this->globalConfigs[$name] = $value;
1173 1
    }
1174
1175
    /**
1176
     * remove an element form the global config list, identified by key
1177
     *
1178
     * @param  string $name The config name
1179
     */
1180 1
    public function removeGlobalConfig($name)
1181
    {
1182 1
        if (isset($this->globalConfigs[$name])) {
1183 1
            unset($this->globalConfigs[$name]);
1184 1
        }
1185 1
    }
1186
1187
    /**
1188
     * get global options list
1189
     *
1190
     * @return array Global options list
1191
     */
1192 93
    public function getGlobalOptions()
1193
    {
1194 93
        return $this->globalOptions;
1195
    }
1196
1197
    /**
1198
     * add a key/value pair to the global option list
1199
     *
1200
     * @param string $name  The option name
1201
     * @param string $value The option value
1202
     */
1203 1
    public function addGlobalOption($name, $value)
1204
    {
1205 1
        $this->globalOptions[$name] = $value;
1206 1
    }
1207
1208
    /**
1209
     * remove an element form the global option list, identified by key
1210
     *
1211
     * @param  string $name The option name
1212
     */
1213 1
    public function removeGlobalOption($name)
1214
    {
1215 1
        if (isset($this->globalOptions[$name])) {
1216 1
            unset($this->globalOptions[$name]);
1217 1
        }
1218 1
    }
1219
1220
    /**
1221
     * get global command arguments list
1222
     *
1223
     * @return array Global command arguments list
1224
     */
1225 93
    public function getGlobalCommandArguments()
1226
    {
1227 93
        return $this->globalCommandArguments;
1228
    }
1229
1230
    /**
1231
     * add a value to the global command argument list
1232
     *
1233
     * @param string $value The command argument
1234
     */
1235 1
    public function addGlobalCommandArgument($value)
1236
    {
1237 1
        if (!in_array($value, $this->globalCommandArguments, true)) {
1238 1
            $this->globalCommandArguments[] = $value;
1239 1
        }
1240 1
    }
1241
1242
    /**
1243
     * remove an element form the global command argument list, identified by 
1244
     * value
1245
     *
1246
     * @param  string $value The command argument
1247
     */
1248 1
    public function removeGlobalCommandArgument($value)
1249
    {
1250 1
        if (in_array($value, $this->globalCommandArguments, true)) {
1251 1
            $index = array_search($value, $this->globalCommandArguments);
1252 1
            unset($this->globalCommandArguments[$index]);
1253 1
        }
1254 1
    }
1255
}
1256