|
1
|
|
|
<?php |
|
2
|
|
|
declare(strict_types=1); |
|
3
|
|
|
|
|
4
|
|
|
namespace SamIT\Yii2\PhpFpm\controllers; |
|
5
|
|
|
|
|
6
|
|
|
|
|
7
|
|
|
use Docker\API\Model\BuildInfo; |
|
8
|
|
|
use Docker\API\Model\PushImageInfo; |
|
9
|
|
|
use Docker\Context\Context; |
|
10
|
|
|
use Docker\Context\ContextBuilder; |
|
11
|
|
|
use Docker\Context\ContextInterface; |
|
12
|
|
|
use Docker\Docker; |
|
13
|
|
|
use Docker\Stream\BuildStream; |
|
14
|
|
|
use Psr\Http\Message\ResponseInterface; |
|
15
|
|
|
use SamIT\Yii2\PhpFpm\Module; |
|
16
|
|
|
use yii\base\InvalidConfigException; |
|
17
|
|
|
use yii\console\Controller; |
|
18
|
|
|
use yii\web\Response; |
|
19
|
|
|
use function Clue\StreamFilter\fun; |
|
20
|
|
|
|
|
21
|
|
|
/** |
|
22
|
|
|
* Class BuildController |
|
23
|
|
|
* @package SamIT\Yii2\PhpFpm\controllers |
|
24
|
|
|
* @property Module $module |
|
25
|
|
|
*/ |
|
26
|
|
|
class BuildController extends Controller |
|
27
|
|
|
{ |
|
28
|
|
|
public $defaultAction = 'build'; |
|
29
|
|
|
|
|
30
|
|
|
/** |
|
31
|
|
|
* @var string The name of the created image |
|
32
|
|
|
* If not explicitly set will take its default from module config. |
|
33
|
|
|
*/ |
|
34
|
|
|
public $image; |
|
35
|
|
|
|
|
36
|
|
|
/** |
|
37
|
|
|
* @var string The tag of the created image |
|
38
|
|
|
* If not explicitly set will take its default from module config. |
|
39
|
|
|
*/ |
|
40
|
|
|
public $tag; |
|
41
|
|
|
|
|
42
|
|
|
/** |
|
43
|
|
|
* @var bool whether to push the image after a successful build. |
|
44
|
|
|
* If not explicitly set will take its default from module config. |
|
45
|
|
|
*/ |
|
46
|
|
|
public $push; |
|
47
|
|
|
|
|
48
|
|
|
/** |
|
49
|
|
|
* @var Docker |
|
50
|
|
|
*/ |
|
51
|
|
|
protected $docker; |
|
52
|
|
|
|
|
53
|
|
|
/** |
|
54
|
|
|
* @var string the user to authenticate against the repository |
|
55
|
|
|
*/ |
|
56
|
|
|
public $user; |
|
57
|
|
|
|
|
58
|
|
|
/** |
|
59
|
|
|
* @var string the password to authenticate against the repository |
|
60
|
|
|
*/ |
|
61
|
|
|
public $password; |
|
62
|
|
|
|
|
63
|
3 |
|
public function init(): void |
|
64
|
|
|
{ |
|
65
|
3 |
|
parent::init(); |
|
66
|
3 |
|
$this->docker = Docker::create(); |
|
67
|
3 |
|
$this->push = $this->module->push; |
|
68
|
3 |
|
$this->image = $this->module->image; |
|
69
|
3 |
|
$this->tag = $this->module->tag; |
|
70
|
3 |
|
} |
|
71
|
|
|
|
|
72
|
2 |
|
public function actionBuild(): void |
|
73
|
|
|
{ |
|
74
|
|
|
|
|
75
|
|
|
|
|
76
|
2 |
|
$params = []; |
|
77
|
2 |
|
if (isset($this->image)) { |
|
78
|
2 |
|
$name = "{$this->image}:{$this->tag}"; |
|
79
|
2 |
|
$params['t'] = $name; |
|
80
|
|
|
} |
|
81
|
2 |
|
$buildStream = $this->createBuildStream($params); |
|
82
|
|
|
|
|
83
|
2 |
|
$buildStream->onFrame(function(BuildInfo $buildInfo): void { |
|
84
|
2 |
|
echo $buildInfo->getStream(); |
|
85
|
2 |
|
}); |
|
86
|
|
|
|
|
87
|
2 |
|
$buildStream->wait(); |
|
88
|
2 |
|
echo "Wait finished\n"; |
|
89
|
2 |
|
$buildStream->wait(); |
|
90
|
|
|
|
|
91
|
2 |
|
if ($this->push) { |
|
92
|
2 |
|
if (!isset($name, $this->user, $this->password)) { |
|
93
|
1 |
|
throw new InvalidConfigException("When using the push option, you must configure or provide user, password and image"); |
|
94
|
|
|
} |
|
95
|
|
|
$params = [ |
|
96
|
1 |
|
'X-Registry-Auth' => \base64_encode(\GuzzleHttp\json_encode([ |
|
97
|
1 |
|
'user' => $this->user, |
|
98
|
1 |
|
'password' => $this->password |
|
99
|
|
|
])) |
|
100
|
|
|
]; |
|
101
|
1 |
|
$pushResult = $this->docker->imagePush($name, $params ?? [], Docker::FETCH_OBJECT); |
|
102
|
|
|
|
|
103
|
1 |
|
if ($pushResult instanceof ResponseInterface) { |
|
104
|
|
|
throw new \Exception($pushResult->getReasonPhrase() . ':' . $pushResult->getBody()->getContents(), $pushResult->getStatusCode()); |
|
105
|
|
|
} |
|
106
|
|
|
/** @var PushImageInfo $pushInfo */ |
|
107
|
1 |
|
$pushInfo = \array_pop($pushResult); |
|
108
|
|
|
|
|
109
|
1 |
|
if (!empty($pushInfo->getError())) { |
|
110
|
1 |
|
throw new \Exception($pushInfo->getError()); |
|
111
|
|
|
} |
|
112
|
|
|
|
|
113
|
|
|
} |
|
114
|
|
|
} |
|
115
|
|
|
|
|
116
|
3 |
|
public function createBuildStream(array $params = []): BuildStream |
|
117
|
|
|
{ |
|
118
|
|
|
|
|
119
|
3 |
|
$context = $this->module->createBuildContext(); |
|
120
|
|
|
|
|
121
|
|
|
/** @var BuildStream $buildStream */ |
|
122
|
3 |
|
$buildStream = $this->docker->imageBuild($context->toStream(), $params, Docker::FETCH_STREAM); |
|
123
|
3 |
|
return $buildStream; |
|
124
|
|
|
} |
|
125
|
|
|
|
|
126
|
1 |
|
public function options($actionID) |
|
127
|
|
|
{ |
|
128
|
|
|
|
|
129
|
1 |
|
$result = parent::options($actionID); |
|
130
|
|
|
switch ($actionID) { |
|
131
|
1 |
|
case 'build': |
|
|
|
|
|
|
132
|
1 |
|
$result[] = 'push'; |
|
133
|
1 |
|
$result[] = 'image'; |
|
134
|
1 |
|
$result[] = 'tag'; |
|
135
|
1 |
|
$result[] = 'user'; |
|
136
|
1 |
|
$result[] = 'password'; |
|
137
|
1 |
|
break; |
|
138
|
|
|
|
|
139
|
|
|
} |
|
140
|
1 |
|
return $result; |
|
141
|
|
|
} |
|
142
|
|
|
|
|
143
|
|
|
public function optionAliases() |
|
144
|
|
|
{ |
|
145
|
|
|
$result = parent::optionAliases(); |
|
146
|
|
|
$result['p'] = 'push'; |
|
147
|
|
|
$result['t'] = 'tag'; |
|
148
|
|
|
$result['i'] = 'image'; |
|
149
|
|
|
$result['u'] = 'user'; |
|
150
|
|
|
$result['P'] = 'password'; |
|
151
|
|
|
return $result; |
|
152
|
|
|
} |
|
153
|
|
|
|
|
154
|
|
|
|
|
155
|
|
|
} |
As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next
break.There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.