Completed
Push — master ( 7e2493...c1f1cb )
by Adam
04:15
created

Bootstrap::invokeTask()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 11
ccs 4
cts 4
cp 1
rs 9.4285
cc 2
eloc 8
nc 2
nop 3
crap 2
1
<?php
2
3
4
namespace Genesis;
5
6
7
use Genesis\Config\Container;
8
use Genesis\Config\ContainerFactory;
9
10
/**
11
 * @author Adam Bisek <[email protected]>
12
 */
13
class Bootstrap
14
{
15
16
	const DEFAULT_CONFIG_FILE = 'config.neon';
17
18
	/** @var BuildFactory */
19
	private $buildFactory;
20
21
	/** @var string */
22
	private $workingDir;
23
24
25
	/**
26
	 * @return BuildFactory
27
	 */
28
	public function getBuildFactory()
29
	{
30
		return $this->buildFactory;
31
	}
32
33
34
	/**
35
	 * @param BuildFactory $buildFactory
36
	 */
37 14
	public function setBuildFactory($buildFactory)
38
	{
39 14
		$this->buildFactory = $buildFactory;
40 14
	}
41
42
43
	/**
44
	 * @param InputArgs $inputArgs
45
	 * @throws TerminateException
46
	 */
47 14
	public function run(InputArgs $inputArgs)
48
	{
49 14
		$this->startup($inputArgs);
50 13
		$arguments = $inputArgs->getArguments();
51 13
		if (isset($arguments[0]) && $arguments[0] === 'self-init') {
52 1
			$directoryName = isset($arguments[1]) ? $arguments[1] : 'build';
53 1
			$selfInit = new Commands\SelfInit();
54 1
			$selfInit->setDistDirectory(__DIR__ . '/build-dist');
55 1
			$selfInit->setWorkingDirectory($this->workingDir);
56 1
			$selfInit->setDirname($directoryName);
57 1
			$selfInit->execute();
58 1
			$this->terminate(0);
59
		}
60 12
		$container = $this->resolveBootstrap();
61 11
		$configFile = $inputArgs->getOption('config') ? $inputArgs->getOption('config') : self::DEFAULT_CONFIG_FILE;
62
		try {
63 11
			$container = $this->createContainer($configFile, $container);
64 11
			$build = $this->createBuild($container, $arguments);
65 11
		} catch (\Throwable $e) { // fault barrier -> catch all
66
			$this->handleException($e);
67 2
		} catch (\Exception $e) { // fault barrier -> catch all, PHP 5.x compatibility
68 2
			$this->handleException($e);
69
		}
70 9
		if (count($arguments) < 1) {
71 2
			$this->invokeTask($build, 'default', $arguments);
72 2
			$this->terminate(0);
73 2
		}
74
75
		try {
76 7
			$this->invokeTask($build, $arguments[0], $arguments);
77 7
		} catch (TerminateException $e) {
78 1
			throw $e; // rethrow -> shutdown imminent
79 1
		} catch (\Throwable $e) { // fault barrier -> catch all
80
			$this->handleException($e);
81 6
		} catch (\Exception $e) { // fault barrier -> catch all, PHP 5.x compatibility
82
			$this->handleException($e);
83 6
		}
84 7
		$this->log("Exited with SUCCESS", 'black', 'green');
85 1
		echo PHP_EOL;
86 1
		$this->terminate(0);
87 1
	}
88
89 5
90 5
	private function terminate($code)
91 5
	{
92
		throw new TerminateException(NULL, $code);
93
	}
94
95 14
96
	private function startup(InputArgs $inputArgs)
97 14
	{
98 1
		$this->workingDir = getcwd();
99
		if ($inputArgs->getOption('colors') !== NULL && !$inputArgs->getOption('colors')) {
100
			Cli::$enableColors = FALSE;
101 14
		}
102
		if ($inputArgs->getOption('working-dir')) {
103 14
			$this->workingDir = realpath($inputArgs->getOption('working-dir'));
104 14
			if (!$this->workingDir) {
105 14
				$this->log(sprintf("Working dir '%s' does not exists.", $inputArgs->getOption('working-dir')), 'red');
106 14
				$this->terminate(255);
107 14
			}
108 14
		}
109 14
		if ($this->workingDir === __DIR__) {
110 1
			$this->log(sprintf("Working dir '%s' is directory with Genesis. You have to choose directory with build.", $this->workingDir), 'red');
111 1
			$this->terminate(255);
112
		}
113 14
	}
114 14
115 1
116 1
	/**
117
	 * @return Container|NULL
118 13
	 */
119
	private function resolveBootstrap()
120
	{
121
		$bootstrapFile = $this->workingDir . DIRECTORY_SEPARATOR . 'bootstrap.php';
122
		if (!is_file($bootstrapFile)) {
123
			$this->log("Info: bootstrap.php was not found in working directory.", 'dark_gray');
124 12
			return NULL;
125
		}
126 12
		$this->log("Info: Found bootstrap.php in working directory.", 'dark_gray');
127 12
		$container = require_once $bootstrapFile;
128 1
		if ($container === 1 || $container === TRUE) { // 1 = success, TRUE = already required
129 1
			return NULL;
130
		} elseif ($container instanceof Container) {
131 11
			return $container;
132 11
		}
133 11
		$this->log("Returned value from bootstrap.php must be instance of 'Genesis\\Container\\Container' or nothing (NULL).", 'red');
134 2
		$this->terminate(255);
135 11
	}
136 10
137
138 1
	/**
139 1
	 * @param $configFile
140
	 * @param Container|NULL $bootstrapContainer
141
	 * @return Container
142
	 */
143
	private function createContainer($configFile, Container $bootstrapContainer = NULL)
144
	{
145
		$factory = new ContainerFactory();
146
		$factory->addConfig($this->workingDir . '/' . $configFile);
147
		if (is_file($this->workingDir . '/config.local.neon')) {
148 11
			$factory->addConfig($this->workingDir . '/config.local.neon');
149
		}
150 11
		$factory->setWorkingDirectory($this->workingDir);
151 11
		if ($bootstrapContainer !== NULL) {
152 11
			$factory->addContainerToMerge($bootstrapContainer);
153
		}
154
		return $factory->create();
155 11
	}
156 11
157 10
158 10
	/**
159 11
	 * @param Container $container
160
	 * @return Build
161
	 */
162
	private function createBuild(Container $container, array $arguments = NULL)
163
	{
164
		if ($this->buildFactory === NULL) {
165
			throw new InvalidStateException("Build factory was not setted.");
166
		}
167 11
		return $this->buildFactory->create($container, $arguments);
168
	}
169 11
170
	/**
171
	 * @param Build $build
172 11
	 * @param $task
173
	 */
174
	private function invokeTask(Build $build, $task, array $arguments = NULL)
175
	{
176
		$method = 'run' . str_replace('-', '', ucfirst($task));
177
		if (!method_exists($build, $method)) {
178
			$this->log("Task '$task' does not exists.", 'red');
179
			$this->terminate(255);
180 3
		}
181
		$this->log("Running [$task]", 'green');
182 3
		$args = array_slice($arguments, 1); // first argument is task name, slice it
183 3
		call_user_func_array([$build, $method], $args);
184 3
	}
185 3
186
187
	/**
188
	 * @param \Exception|\Throwable $e
189
	 * @throws TerminateException
190
	 */
191
	private function handleException($e)
192
	{
193
		$this->log("Exited with ERROR:", 'red');
194 13
		$this->log($e->getMessage(), 'red');
195
		echo $e->getTraceAsString() . PHP_EOL;
196 13
		$this->terminate(255);
197 13
	}
198
199
200
	/**
201
	 * @param string $message
202
	 * @param string|null $color
203
	 * @param string|null $backgroundColor
204
	 */
205
	private function log($message, $color = NULL, $backgroundColor = NULL)
206
	{
207
		echo Cli::getColoredString($message . PHP_EOL, $color, $backgroundColor);
208
	}
209
210
}