Completed
Push — master ( c1f1cb...e80649 )
by Adam
04:46 queued 01:19
created

Bootstrap   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 199
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 85.98%

Importance

Changes 14
Bugs 1 Features 7
Metric Value
wmc 34
c 14
b 1
f 7
lcom 1
cbo 7
dl 0
loc 199
ccs 92
cts 107
cp 0.8598
rs 9.2

11 Methods

Rating   Name   Duplication   Size   Complexity  
A getBuildFactory() 0 4 1
A setBuildFactory() 0 4 1
F run() 0 41 11
A terminate() 0 4 1
B startup() 0 18 6
B resolveBootstrap() 0 17 5
A createContainer() 0 13 3
A createBuild() 0 7 2
A invokeTask() 0 11 2
A handleException() 0 7 1
A log() 0 4 1
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
		}
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 1
		} catch (\Exception $e) { // fault barrier -> catch all, PHP 5.x compatibility
82 1
			$this->handleException($e);
83
		}
84 6
		$this->log("Exited with SUCCESS", 'black', 'green');
85 6
		echo PHP_EOL;
86 5
		$this->terminate(0);
87
	}
88
89
90 14
	private function terminate($code)
91
	{
92 14
		throw new TerminateException(NULL, $code);
93
	}
94
95
96 14
	private function startup(InputArgs $inputArgs)
97
	{
98 14
		$this->workingDir = getcwd();
99 14
		if ($inputArgs->getOption('colors') !== NULL && !$inputArgs->getOption('colors')) {
100 14
			Cli::$enableColors = FALSE;
101 14
		}
102 14
		if ($inputArgs->getOption('working-dir')) {
103 14
			$this->workingDir = realpath($inputArgs->getOption('working-dir'));
104 14
			if (!$this->workingDir) {
105 1
				$this->log(sprintf("Working dir '%s' does not exists.", $inputArgs->getOption('working-dir')), 'red');
106 1
				$this->terminate(255);
107
			}
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 13
	}
114
115
116
	/**
117
	 * @return Container|NULL
118
	 */
119 12
	private function resolveBootstrap()
120
	{
121 12
		$bootstrapFile = $this->workingDir . DIRECTORY_SEPARATOR . 'bootstrap.php';
122 12
		if (!is_file($bootstrapFile)) {
123 1
			$this->log("Info: bootstrap.php was not found in working directory.", 'dark_gray');
124 1
			return NULL;
125
		}
126 11
		$this->log("Info: Found bootstrap.php in working directory.", 'dark_gray');
127 11
		$container = require_once $bootstrapFile;
128 11
		if ($container === 1 || $container === TRUE) { // 1 = success, TRUE = already required
129 2
			return NULL;
130 11
		} elseif ($container instanceof Container) {
131 10
			return $container;
132
		}
133 1
		$this->log("Returned value from bootstrap.php must be instance of 'Genesis\\Container\\Container' or nothing (NULL).", 'red');
134 1
		$this->terminate(255);
135
	}
136
137
138
	/**
139
	 * @param $configFile
140
	 * @param Container|NULL $bootstrapContainer
141
	 * @return Container
142
	 */
143 11
	private function createContainer($configFile, Container $bootstrapContainer = NULL)
144
	{
145 11
		$factory = new ContainerFactory();
146 11
		$factory->addConfig($this->workingDir . '/' . $configFile);
147 11
		if (is_file($this->workingDir . '/config.local.neon')) {
148
			$factory->addConfig($this->workingDir . '/config.local.neon');
149
		}
150 11
		$factory->setWorkingDirectory($this->workingDir);
151 11
		if ($bootstrapContainer !== NULL) {
152 10
			$factory->addContainerToMerge($bootstrapContainer);
153 10
		}
154 11
		return $factory->create();
155
	}
156
157
158
	/**
159
	 * @param Container $container
160
	 * @return Build
161
	 */
162 11
	private function createBuild(Container $container, array $arguments)
163
	{
164 11
		if ($this->buildFactory === NULL) {
165
			throw new InvalidStateException("Build factory was not setted.");
166
		}
167 11
		return $this->buildFactory->create($container, $arguments);
168
	}
169
170
	/**
171
	 * @param Build $build
172
	 * @param $task
173
	 * @param array|NULL $arguments
174
	 */
175 9
	private function invokeTask(Build $build, $task, array $arguments)
176
	{
177 9
		$method = 'run' . str_replace('-', '', ucfirst($task));
178 9
		if (!method_exists($build, $method)) {
179 1
			$this->log("Task '$task' does not exists.", 'red');
180 1
			$this->terminate(255);
181
		}
182 8
		$this->log("Running [$task]", 'green');
183 8
		$args = array_slice($arguments, 1); // first argument is task name, slice it
184 8
		call_user_func_array([$build, $method], $args);
185 7
	}
186
187
188
	/**
189
	 * @param \Exception|\Throwable $e
190
	 * @throws TerminateException
191
	 */
192 3
	private function handleException($e)
193
	{
194 3
		$this->log("Exited with ERROR:", 'red');
195 3
		$this->log($e->getMessage(), 'red');
196 3
		echo $e->getTraceAsString() . PHP_EOL;
197 3
		$this->terminate(255);
198
	}
199
200
201
	/**
202
	 * @param string $message
203
	 * @param string|null $color
204
	 * @param string|null $backgroundColor
205
	 */
206 13
	private function log($message, $color = NULL, $backgroundColor = NULL)
207
	{
208 13
		echo Cli::getColoredString($message . PHP_EOL, $color, $backgroundColor);
209 13
	}
210
211
}