LocalGitRepoClient::gitArchiveFile()   C
last analyzed

Complexity

Conditions 9
Paths 18

Size

Total Lines 48
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
dl 0
loc 48
ccs 0
cts 48
cp 0
rs 5.5102
c 0
b 0
f 0
cc 9
eloc 37
nc 18
nop 6
crap 90
1
<?php
2
3
namespace ConfigToken\FileClient\Types;
4
5
6
use ConfigToken\ConnectionSettings\Types\LocalGitRepoConnectionSettings;
7
use ConfigToken\FileClient\Exception\ContentFormatException;
8
use ConfigToken\FileClient\Exception\FileClientConnectionException;
9
use ConfigToken\FileUtils;
10
11
class LocalGitRepoClient extends AbstractFileClient
12
{
13
    /**
14
     * Get the file server type identifier corresponding to the client's implementation.
15
     *
16
     * @return string
17
     */
18
    public static function getServerType()
19
    {
20
        return 'git';
21
    }
22
23
    /**
24
     * Call 'git archive --remote' to fetch the contents of a single file.
25
     *
26
     * @param string $hostName The host name of the Git repository.
27
     * @param string $groupName The group name of the Git repository.
28
     * @param string $repo The Git repository name.
29
     * @param string $fileName The file name from the Git repository
30
     * @param string $namedReference The named reference (tag or branch) for the Git repository.
31
     * @param string $git The local path of the "git" executable.
32
     * @return string
33
     * @throws FileClientConnectionException
34
     * @throws ContentFormatException
35
     */
36
    public static function gitArchiveFile($hostName, $groupName, $repo, $fileName, $namedReference='HEAD', $git='git')
37
    {
38
        $fileName = str_replace('\\', '/', $fileName);
39
        $descriptorSpec = array(
40
            1 => array('pipe', 'w'),
41
            2 => array('pipe', 'w'),
42
        );
43
        $pipes = array();
44
        $command = sprintf(
45
            '%s archive --format=zip --remote git@%s:%s/%s.git %s %s',
46
            $git,
47
            $hostName,
48
            $groupName,
49
            $repo,
50
            $namedReference,
51
            $fileName
52
        );
53
        $resource = proc_open($command, $descriptorSpec, $pipes);
54
        $stdout = stream_get_contents($pipes[1]);
55
        $stderr = stream_get_contents($pipes[2]);
56
        foreach ($pipes as $pipe) {
57
            fclose($pipe);
58
        }
59
        $status = trim(proc_close($resource));
60
        if ($status) throw new FileClientConnectionException($stderr);
61
        if ($stderr != '') {
62
            throw new FileClientConnectionException(sprintf('%s: %s', $command, $stderr));
63
        }
64
        if (strpos($stdout, 'fatal: no such ref:') > -1) {
65
            throw new FileClientConnectionException(sprintf('%s: Unknown reference (tag or branch).', $command));
66
        }
67
        if (strpos($stdout, 'fatal: The remote end hung up unexpectedly.') > -1) {
68
            throw new FileClientConnectionException(sprintf('%s: Problem connecting to remote.', $command));
69
        }
70
        if (strpos($stdout, 'remote: git upload-archive: archiver died with error.') > -1) {
71
            throw new FileClientConnectionException(sprintf('%s: File not found.', $command));
72
        }
73
        if (strlen($stdout) <= 30) {
74
            throw new FileClientConnectionException(sprintf('%s: Empty response.', $command));
75
        }
76
        try {
77
            $head = unpack("Vsig/vver/vflag/vmeth/vmodt/vmodd/Vcrc/Vcsize/Vsize/vnamelen/vexlen", substr($stdout, 0, 30));
78
            $content = gzinflate(substr($stdout, 30 + $head['namelen'] + $head['exlen'], $head['csize']));
79
        } catch (\Exception $e) {
80
            throw new ContentFormatException(sprintf('%s: Bad response: %s.', $command, $e->getMessage()));
81
        }
82
        return $content;
83
    }
84
85
    /**
86
     * Return the file contents.
87
     *
88
     * @param string $fileName
89
     * @throws \Exception
90
     * @return array(string, string) [$contentType, $content]
0 ignored issues
show
Documentation introduced by
The doc-type array(string, could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
91
     */
92
    public function readFile($fileName)
93
    {
94
        $this->validateConnectionSettings();
95
        /** @var LocalGitRepoConnectionSettings $connectionSettings */
96
        $connectionSettings = $this->getConnectionSettings();
97
        $content = $this->gitArchiveFile(
98
            $connectionSettings->getHostName(),
99
            $connectionSettings->getGroupName(),
100
            $connectionSettings->getRepoName(),
101
            $fileName,
102
            $connectionSettings->getNamedReference(),
103
            $connectionSettings->getGitExecutable()
104
        );
105
        $contentType = FileUtils::getContentTypeFromFileName($fileName);
106
        return array($contentType, $content);
107
    }
108
}