Completed
Push — master ( 651eb5...e7f95e )
by Tomáš
16:52 queued 15:34
created

GitWrapper::setTimeout()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GitWrapper;
6
7
use GitWrapper\Event\GitOutputEvent;
8
use GitWrapper\EventSubscriber\AbstractOutputEventSubscriber;
9
use GitWrapper\EventSubscriber\GitLoggerEventSubscriber;
10
use GitWrapper\EventSubscriber\StreamOutputEventSubscriber;
11
use GitWrapper\Exception\GitException;
12
use GitWrapper\Process\GitProcess;
13
use GitWrapper\Strings\GitStrings;
14
use Symfony\Component\EventDispatcher\EventDispatcher;
15
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
16
use Symfony\Component\Process\ExecutableFinder;
17
18
/**
19
 * A wrapper class around the Git binary.
20
 *
21
 * A GitWrapper object contains the necessary context to run Git commands such
22
 * as the path to the Git binary and environment variables. It also provides
23
 * helper methods to run Git commands as set up the connection to the GIT_SSH
24
 * wrapper script.
25
 */
26
final class GitWrapper
27
{
28
    /**
29
     * Path to the Git binary.
30
     *
31
     * @var string
32
     */
33
    private $gitBinary;
34
35
    /**
36
     * The timeout of the Git command in seconds.
37
     *
38
     * @var int
39
     */
40
    private $timeout = 60;
41
42
    /**
43
     * Environment variables defined in the scope of the Git command.
44
     *
45
     * @var string[]
46
     */
47
    private $env = [];
48
49
    /**
50
     * @var AbstractOutputEventSubscriber
51
     */
52
    private $outputEventSubscriber;
53
54
    /**
55
     * @var EventDispatcherInterface
56
     */
57
    private $eventDispatcher;
58
59
    public function __construct(?string $gitBinary = null)
60
    {
61
        if ($gitBinary === null) {
62
            $finder = new ExecutableFinder();
63
            $gitBinary = $finder->find('git');
64
            if (! $gitBinary) {
65
                throw new GitException('Unable to find the Git executable.');
66
            }
67
        }
68
69
        $this->setGitBinary($gitBinary);
70
71
        $this->eventDispatcher = new EventDispatcher();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Symfony\Component\E...tcher\EventDispatcher() of type object<Symfony\Component...atcher\EventDispatcher> is incompatible with the declared type object<Symfony\Component...entDispatcherInterface> of property $eventDispatcher.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
72
    }
73
74
    public function getDispatcher(): EventDispatcherInterface
75
    {
76
        return $this->eventDispatcher;
77
    }
78
79
    public function setDispatcher(EventDispatcherInterface $eventDispatcher): void
80
    {
81
        $this->eventDispatcher = $eventDispatcher;
82
    }
83
84
    public function setGitBinary(string $gitBinary): void
85
    {
86
        $this->gitBinary = $gitBinary;
87
    }
88
89
    public function getGitBinary(): string
90
    {
91
        return $this->gitBinary;
92
    }
93
94
    /**
95
     * @param mixed $value
96
     */
97
    public function setEnvVar(string $var, $value): void
98
    {
99
        $this->env[$var] = $value;
100
    }
101
102
    public function unsetEnvVar(string $var): void
103
    {
104
        unset($this->env[$var]);
105
    }
106
107
    /**
108
     * Returns an environment variable that is defined only in the scope of the
109
     * Git command.
110
     *
111
     * @param string $var The name of the environment variable, e.g. "HOME", "GIT_SSH".
112
     * @param mixed $default The value returned if the environment variable is not set, defaults to
113
     *   null.
114
     *
115
     * @return mixed
116
     */
117
    public function getEnvVar(string $var, $default = null)
118
    {
119
        return $this->env[$var] ?? $default;
120
    }
121
122
    /**
123
     * @return mixed[]
124
     */
125
    public function getEnvVars(): array
126
    {
127
        return $this->env;
128
    }
129
130
    public function setTimeout(int $timeout): void
131
    {
132
        $this->timeout = $timeout;
133
    }
134
135
    public function getTimeout(): int
136
    {
137
        return $this->timeout;
138
    }
139
140
    /**
141
     * Set an alternate private key used to connect to the repository.
142
     *
143
     * This method sets the GIT_SSH environment variable to use the wrapper
144
     * script included with this library. It also sets the custom GIT_SSH_KEY
145
     * and GIT_SSH_PORT environment variables that are used by the script.
146
     *
147
     * @param string|null $wrapper Path the the GIT_SSH wrapper script, defaults to null which uses the
148
     *   script included with this library.
149
     */
150
    public function setPrivateKey(string $privateKey, int $port = 22, ?string $wrapper = null): void
151
    {
152
        if ($wrapper === null) {
153
            $wrapper = __DIR__ . '/../bin/git-ssh-wrapper.sh';
154
        }
155
156
        if (! $wrapperPath = realpath($wrapper)) {
157
            throw new GitException('Path to GIT_SSH wrapper script could not be resolved: ' . $wrapper);
158
        }
159
160
        if (! $privateKeyPath = realpath($privateKey)) {
161
            throw new GitException('Path private key could not be resolved: ' . $privateKey);
162
        }
163
164
        $this->setEnvVar('GIT_SSH', $wrapperPath);
165
        $this->setEnvVar('GIT_SSH_KEY', $privateKeyPath);
166
        $this->setEnvVar('GIT_SSH_PORT', $port);
167
    }
168
169
    /**
170
     * Unsets the private key by removing the appropriate environment variables.
171
     */
172
    public function unsetPrivateKey(): void
173
    {
174
        $this->unsetEnvVar('GIT_SSH');
175
        $this->unsetEnvVar('GIT_SSH_KEY');
176
        $this->unsetEnvVar('GIT_SSH_PORT');
177
    }
178
179
    public function addOutputEventSubscriber(AbstractOutputEventSubscriber $gitOutputEventSubscriber): void
180
    {
181
        $this->getDispatcher()->addSubscriber($gitOutputEventSubscriber);
182
    }
183
184
    public function addLoggerEventSubscriber(GitLoggerEventSubscriber $gitLoggerEventSubscriber): void
185
    {
186
        $this->getDispatcher()->addSubscriber($gitLoggerEventSubscriber);
187
    }
188
189
    public function removeOutputEventSubscriber(AbstractOutputEventSubscriber $gitOutputEventSubscriber): void
190
    {
191
        $this->getDispatcher()->removeSubscriber($gitOutputEventSubscriber);
192
    }
193
194
    /**
195
     * Set whether or not to stream real-time output to STDOUT and STDERR.
196
     */
197
    public function streamOutput(bool $streamOutput = true): void
198
    {
199
        if ($streamOutput && ! isset($this->outputEventSubscriber)) {
200
            $this->outputEventSubscriber = new StreamOutputEventSubscriber();
201
            $this->addOutputEventSubscriber($this->outputEventSubscriber);
202
        }
203
204
        if (! $streamOutput && isset($this->outputEventSubscriber)) {
205
            $this->removeOutputEventSubscriber($this->outputEventSubscriber);
206
            unset($this->outputEventSubscriber);
207
        }
208
    }
209
210
    /**
211
     * Returns an object that interacts with a working copy.
212
     *
213
     * @param string $directory Path to the directory containing the working copy.
214
     */
215
    public function workingCopy(string $directory): GitWorkingCopy
216
    {
217
        return new GitWorkingCopy($this, $directory);
218
    }
219
220
    /**
221
     * Returns the version of the installed Git client.
222
     */
223
    public function version(): string
224
    {
225
        return $this->git('--version');
226
    }
227
228
    /**
229
     * Executes a `git init` command.
230
     *
231
     * Create an empty git repository or reinitialize an existing one.
232
     *
233
     * @param mixed[] $options An associative array of command line options.
234
     */
235
    public function init(string $directory, array $options = []): GitWorkingCopy
236
    {
237
        $git = $this->workingCopy($directory);
238
        $git->init($options);
239
        $git->setCloned(true);
240
241
        return $git;
242
    }
243
244
    /**
245
     * Executes a `git clone` command and returns a working copy object.
246
     *
247
     * Clone a repository into a new directory. Use @see GitWorkingCopy::cloneRepository()
248
     * instead for more readable code.
249
     *
250
     * @param string $directory The directory that the repository will be cloned into. If null is
251
     *   passed, the directory will be generated from the URL with @see GitStrings::parseRepositoryName().
252
     * @param mixed[] $options
253
     */
254
    public function cloneRepository(string $repository, ?string $directory = null, array $options = []): GitWorkingCopy
255
    {
256
        if ($directory === null) {
257
            $directory = GitStrings::parseRepositoryName($repository);
258
        }
259
260
        $git = $this->workingCopy($directory);
261
        $git->cloneRepository($repository, $options);
262
        $git->setCloned(true);
263
        return $git;
264
    }
265
266
    /**
267
     * The command is simply a raw command line entry for everything after the Git binary.
268
     * For example, a `git config -l` command would be passed as `config -l` via the first argument of this method.
269
     *
270
     * @return string The STDOUT returned by the Git command.
271
     */
272
    public function git(string $commandLine, ?string $cwd = null): string
273
    {
274
        $command = new GitCommand($commandLine);
275
        $command->executeRaw(is_string($commandLine));
276
        $command->setDirectory($cwd);
277
        return $this->run($command);
278
    }
279
280
    /**
281
     * @return string The STDOUT returned by the Git command.
282
     */
283
    public function run(GitCommand $gitCommand, ?string $cwd = null): string
284
    {
285
        $process = new GitProcess($this, $gitCommand, $cwd);
286
        $process->run(function ($type, $buffer) use ($process, $gitCommand): void {
287
            $event = new GitOutputEvent($this, $process, $gitCommand, $type, $buffer);
288
            $this->getDispatcher()->dispatch($event);
289
        });
290
291
        return $gitCommand->notBypassed() ? $process->getOutput() : '';
292
    }
293
}
294