Passed
Push — main ( f0911f...cd99fe )
by Sebastian
05:24
created

PHP::getStdInHandling()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 11
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 21
ccs 14
cts 14
cp 1
crap 2
rs 9.9
1
<?php
2
3
/**
4
 * This file is part of CaptainHook
5
 *
6
 * (c) Sebastian Feldmann <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace CaptainHook\App\Hook\Template\Local;
15
16
use CaptainHook\App\CH;
17
use CaptainHook\App\Hook\Template;
18
use CaptainHook\App\Hooks;
19
use SebastianFeldmann\Camino\Path;
20
use SebastianFeldmann\Camino\Path\Directory;
21
22
/**
23
 * Local class
24
 *
25
 * Generates the sourcecode for the php hook scripts in .git/hooks/*.
26
 *
27
 * @package CaptainHook
28
 * @author  Sebastian Feldmann <[email protected]>
29
 * @link    https://github.com/captainhookphp/captainhook
30
 * @since   Class available since Release 4.3.0
31
 */
32
class PHP extends Template\Local
33
{
34
    /**
35
     * Return the code for the git hook scripts
36
     *
37
     * @param  string $hook Name of the hook to generate the sourcecode for
38
     * @return array<string>
39
     */
40 7
    public function getHookLines(string $hook): array
41
    {
42 7
        return $this->isPhar ? $this->getPharHookLines($hook) : $this->getSrcHookLines($hook);
43
    }
44
45
    /**
46
     * Returns lines of code for the local src installation
47
     *
48
     * @param  string $hook
49
     * @return array<string>
50
     */
51 4
    private function getSrcHookLines(string $hook): array
52
    {
53 4
        $configPath = $this->pathInfo->getConfigPath();
54 4
        $bootstrap  = $this->config->getBootstrap();
55 4
        $stdIn      = $this->getStdInHandling($hook);
56
57 4
        return array_merge(
58 4
            [
59 4
                '#!/usr/bin/env php',
60 4
                '<?php',
61 4
                '',
62 4
                '# installed by CaptainHook ' . CH::VERSION,
63 4
                '',
64 4
                'use CaptainHook\App\Console\Application as CaptainHook;',
65 4
                'use SebastianFeldmann\Cli\Reader\StandardInput;',
66 4
                'use Symfony\Component\Console\Input\ArgvInput;',
67 4
                '',
68 4
                '(static function($argv)',
69 4
                '{',
70 4
                '    $bootstrap = \'' . dirname($configPath) . '/' . $bootstrap . '\';',
71 4
                '    if (!file_exists($bootstrap)) {',
72 4
                '        fwrite(STDERR, \'Boostrap file \\\'\' . $bootstrap . \'\\\' could not be found\');',
73 4
                '        exit(1);',
74 4
                '    }',
75 4
                '    require $bootstrap;',
76 4
                '',
77 4
            ],
78 4
            $stdIn,
79 4
            [
80 4
                '    $argv = array_merge(',
81 4
                '        [',
82 4
                '            $argv[0],',
83 4
                '            \'hook:' . $hook . '\',',
84 4
                '            \'--configuration=' . $configPath . '\',',
85 4
                '            \'--git-directory=\' . dirname(__DIR__, 2) . \'/.git\',',
86 4
                '            \'--input=\' . trim($input) . \'\',',
87 4
                '        ],',
88 4
                '        array_slice($argv, 1)',
89 4
                '    );',
90 4
                '    $captainHook = new CaptainHook($argv[0]);',
91 4
                '    $captainHook->run(new ArgvInput($argv));',
92 4
                '}',
93 4
                ')($argv);',
94 4
            ]
95 4
        );
96
    }
97
98
    /**
99
     * Returns the lines of code for the local phar installation
100
     *
101
     * @param  string $hook
102
     * @return array<string>
103
     */
104 3
    private function getPharHookLines(string $hook): array
105
    {
106 3
        $configPath     = $this->pathInfo->getConfigPath();
107 3
        $executablePath = $this->pathInfo->getExecutablePath();
108 3
        $bootstrap      = $this->config->getBootstrap();
109 3
        $stdIn          = $this->getStdInHandling($hook);
110
111 3
        $executableInclude = substr($executablePath, 0, 1) == '/'
112 1
                           ? '\'' . $executablePath . '\''
113 2
                           : '__DIR__ . \'/../../' . $executablePath  . '\'';
114 3
        return array_merge(
115 3
            [
116 3
                '#!/usr/bin/env php',
117 3
                '<?php',
118 3
                '',
119 3
                '(static function($argv)',
120 3
                '{',
121 3
            ],
122 3
            $stdIn,
123 3
            [
124 3
                '    $argv = array_merge(',
125 3
                '        [',
126 3
                '            $argv[0],',
127 3
                '            \'hook:' . $hook . '\',',
128 3
                '            \'--configuration=' . $configPath . ',',
129 3
                '            \'--git-directory=\' . dirname(__DIR__, 2) . \'/.git\',',
130 3
                '            \'--bootstrap=' . $bootstrap . '\',',
131 3
                '            \'--input=\' . trim($input) . \'\',',
132 3
                '        ],',
133 3
                '        array_slice($argv, 1)',
134 3
                '    );',
135 3
                '    include ' . $executableInclude . ';',
136 3
                '}',
137 3
                ')($argv);',
138 3
            ]
139 3
        );
140
    }
141
142
    /**
143
     * Read data from stdIn or allow hooks to ask for user input
144
     *
145
     * @param  string $hook
146
     * @return string[]
147
     */
148 7
    private function getStdInHandling(string $hook): array
149
    {
150
        // if the hook supplies input via std in we have to read that data
151
        // then we can't support reading user input from the TTY anymore
152 7
        $useStdIn = [
153 7
            '    $stdIn = new StandardInput(STDIN);',
154 7
            '    $i     = [];',
155 7
            '    foreach ($stdIn as $line) {',
156 7
            '        $i[] = $line;',
157 7
            '    }',
158 7
            '    $input = implode(PHP_EOL, $i);',
159 7
            '',
160 7
        ];
161
162
        // if the hook does not receive data via stdIn ignore it and just use the tty
163
        // sp the user can be asked for some input
164 7
        $useTTY = [
165 7
            '    $input     = \'\';'
166 7
        ];
167
168 7
        return Hooks::receivesStdIn($hook) ? $useStdIn : $useTTY;
169
    }
170
}
171