Test Failed
Push — master ( 13ad3b...564431 )
by Mihail
01:52
created

Application::deploidStructureClean()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 32
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
cc 6
eloc 21
nc 6
nop 1
dl 0
loc 32
ccs 0
cts 20
cp 0
crap 42
rs 8.9617
c 0
b 0
f 0
1
<?php
2
3
namespace Deploid;
4
5
use Symfony\Component\Console\Application as ConsoleApplication;
6
use Psr\Log\LoggerAwareInterface;
7
use Psr\Log\LoggerInterface;
8
use Symfony\Component\Process\Process;
9
10
class Application extends ConsoleApplication implements LoggerAwareInterface {
11
12
	/** @var string */
13
	private $releaseNameFormat = 'Y-m-d_H-i-s';
14
15
	/** @var array */
16
	private $structure = [
17
		'dirs' => [
18
			'releases',
19
			'releases/first',
20
			'shared',
21
		],
22
		'files' => [
23
			'deploid.log',
24
		],
25
		'links' => [
26
			'current:releases/first',
27
		],
28
	];
29
30
	/** @var LoggerInterface */
31
	private $logger;
32
33
	/* mutators */
34
35
	public function getReleaseNameFormat() {
36
		return $this->releaseNameFormat;
37
	}
38
39
	public function setReleaseNameFormat($releaseNameFormat) {
40
		$this->releaseNameFormat = $releaseNameFormat;
41
	}
42
43
	/**
44
	 * @return LoggerInterface
45
	 */
46
	public function getLogger() {
47
		return $this->logger;
48
	}
49
50
	/**
51
	 * @param LoggerInterface $logger
52
	 * @return void
53
	 */
54
	public function setLogger(LoggerInterface $logger) {
55
		$this->logger = $logger;
56
	}
57
58
	public function getStructure() {
59
		return $this->structure;
60
	}
61
62
	public function setStructure(array $structure) {
63
		$this->structure = $structure;
64
	}
65
66
	public function makeStructure($path, array $structure) {
67
		if (empty($path)) throw new \InvalidArgumentException('empty path');
68
		if (empty($structure)) throw new \InvalidArgumentException('empty structure');
69
70
		foreach ($structure as $section => $items) {
71
			foreach ($items as $item) {
72
				if ($section == 'dirs' && strlen($item)) mkdir($path . DIRECTORY_SEPARATOR . $item, 0777, true);
73
				if ($section == 'files' && strlen($item)) touch($path . DIRECTORY_SEPARATOR . $item);
74
				if ($section == 'links' && strlen($item)) symlink($path . DIRECTORY_SEPARATOR . (explode(':', $item)[1]), $path . DIRECTORY_SEPARATOR . (explode(':', $item)[0]));
75
			}
76
		}
77
78
		return true;
79
	}
80
81
	/* tools */
82
83
	/**
84
	 * @param string $path
85
	 * @return \Deploid\Payload
86
	 */
87
	public function deploidStructureValidate($path) {
88
		$payload = new Payload();
89
90
		$path = $this->absolutePath($path, getcwd());
91
92
		$releasesDir = realpath($path) . DIRECTORY_SEPARATOR . 'releases';
93 1
		if (!is_dir($releasesDir)) {
94 1
			$payload->setType(Payload::STRUCTURE_VALIDATE_FAIL);
95
			$payload->setMessage('directory "' . $releasesDir . '" does not exist');
96 1
			$payload->setCode(255);
97
			return $payload;
98
		}
99
100
		$sharedDir = realpath($path) . DIRECTORY_SEPARATOR . 'shared';
101
		if (!is_dir($sharedDir)) {
102
			$payload->setType(Payload::STRUCTURE_VALIDATE_FAIL);
103 1
			$payload->setMessage('directory "' . $sharedDir . '" does not exist');
104 1
			$payload->setCode(255);
105
			return $payload;
106 1
		}
107 1
108 1
		$logFile = realpath($path) . DIRECTORY_SEPARATOR . 'deploid.log';
109 1
		if (!is_file($logFile)) {
110
			$payload->setType(Payload::STRUCTURE_VALIDATE_FAIL);
111
			$payload->setMessage('file "' . $logFile . '" does not exist');
112
			$payload->setCode(255);
113
			return $payload;
114
		}
115 1
116
		$payload->setType(Payload::STRUCTURE_VALIDATE_SUCCESS);
117 1
		$payload->setMessage('structure is valid');
118 1
		$payload->setCode(0);
119 1
		return $payload;
120 1
	}
121 1
122
	/**
123
	 * @param string $path
124
	 * @return \Deploid\Payload
125
	 */
126
	public function deploidStructureInit($path) {
127 1
		$payload = new Payload();
128
129 1
		if (!strlen($path)) {
130 1
			$payload->setType(Payload::STRUCTURE_INIT_FAIL);
131 1
			$payload->setMessage('empty path');
132 1
			$payload->setCode(255);
133 1
			return $payload;
134
		}
135
136
		$path = $this->absolutePath($path, getcwd());
137
		$messages = [];
138
139 1
		if (!is_dir($path)) {
140
			if (mkdir($path, 0777, true)) {
141 1
				$messages[] = 'directory "' . realpath($path) . '" created';
142 1
			} else {
143 1
				$payload->setType(Payload::STRUCTURE_INIT_FAIL);
144 1
				$payload->setMessage('directory "' . $path . '" does not created');
145 1
				$payload->setCode(255);
146
				return $payload;
147
			}
148
		}
149
150
		$releasesDir = $path . DIRECTORY_SEPARATOR . 'releases';
151 1
		if (!is_dir($releasesDir)) {
152
			if (mkdir($releasesDir, 0777, true)) {
153 1
				$messages[] = 'directory "' . realpath($releasesDir) . '" created';
154 1
			} else {
155 1
				$payload->setType(Payload::STRUCTURE_INIT_FAIL);
156 1
				$payload->setMessage('directory "' . $releasesDir . '" does not created');
157
				$payload->setCode(255);
158
				return $payload;
159
			}
160
		}
161
162
		$sharedDir = $path . DIRECTORY_SEPARATOR . 'shared';
163 1
		if (!is_dir($sharedDir)) {
164 1
			if (mkdir($sharedDir, 0777, true)) {
165
				$messages[] = 'directory "' . realpath($sharedDir) . '" created';
166 1
			} else {
167
				$payload->setType(Payload::STRUCTURE_INIT_FAIL);
168
				$payload->setMessage('directory "' . $sharedDir . '" does not created');
169
				$payload->setCode(255);
170
				return $payload;
171
			}
172
		}
173 1
174
		$logFile = $path . DIRECTORY_SEPARATOR . 'deploid.log';
175 1
		if (!is_file($logFile)) {
176
			if (touch($logFile)) {
177
				$messages[] = 'file "' . realpath($logFile) . '" created';
178 1
			} else {
179 1
				$payload->setType(Payload::STRUCTURE_INIT_FAIL);
180
				$payload->setMessage('file"' . $logFile . '" does not created');
181 1
				$payload->setCode(255);
182 1
				return $payload;
183 1
			}
184 1
		}
185 1
186 1
		$payload->setType(Payload::STRUCTURE_INIT_SUCCESS);
187 1
		$payload->setMessage($messages);
188
		$payload->setCode(0);
189 1
		return $payload;
190 1
	}
191 1
192 1
	/**
193
	 * @param string $path
194
	 * @return \Deploid\Payload
195
	 */
196
	public function deploidStructureClean($path) {
197
		$payload = new Payload();
198
199
		if (!strlen($path)) {
200
			$payload->setType(Payload::STRUCTURE_CLEAN_FAIL);
201
			$payload->setMessage('empty path');
202
			$payload->setCode(255);
203
			return $payload;
204
		}
205
206
		$path = $this->absolutePath($path, getcwd());
207
208
		$paths = glob(realpath($path) . DIRECTORY_SEPARATOR . '*');
209
210
		$paths = array_filter($paths, function ($path) {
211
			return !in_array(basename($path), $this->structure['dirs'] + $this->structure['links'] + $this->structure['files']);
212
		});
213
214
		foreach ($paths as $pathname) {
215
			if (is_file($pathname)) {
216
				unlink($pathname);
217
			} else if (is_link($pathname)) {
218
				unlink($pathname);
219
			} else if (is_dir($pathname)) {
220
				rmdir($pathname);
221
			}
222
		}
223
224
		$payload->setType(Payload::STRUCTURE_CLEAN_SUCCESS);
225
		$payload->setMessage(array_merge(['cleaned items:'], $paths));
226
		$payload->setCode(0);
227
		return $payload;
228
	}
229
230
	/**
231
	 * @param string $release
232
	 * @param string $path
233
	 * @return \Deploid\Payload
234
	 */
235
	public function deploidReleaseExist($release, $path) {
236
		$payload = new Payload();
237
238
		if (!strlen($release)) {
239
			$payload->setType(Payload::RELEASE_EXIST_FAIL);
240
			$payload->setMessage('empty release name');
241
			$payload->setCode(255);
242
			return $payload;
243
		}
244
245
		if (!strlen($path)) {
246
			$payload->setType(Payload::RELEASE_EXIST_FAIL);
247
			$payload->setMessage('empty path');
248
			$payload->setCode(255);
249
			return $payload;
250
		}
251
252
		$path = $this->absolutePath($path, getcwd());
253
254
		$releaseDir = $path . DIRECTORY_SEPARATOR . 'releases' . DIRECTORY_SEPARATOR . $release;
255
		if (!is_dir($releaseDir)) {
256
			$payload->setType(Payload::RELEASE_EXIST_FAIL);
257
			$payload->setMessage('release "' . $release . '" does not exist');
258
			$payload->setCode(255);
259
			return $payload;
260
		}
261
262
		$payload->setType(Payload::RELEASE_EXIST_SUCCESS);
263
		$payload->setMessage('release "' . $release . '" exist');
264
		$payload->setCode(0);
265
		return $payload;
266
	}
267
268
	/**
269
	 * @param string $release
270
	 * @param string $path
271
	 * @return \Deploid\Payload
272
	 */
273
	public function deploidReleaseCreate($release, $path) {
274
		$payload = new Payload();
275
276
		if (!strlen($release)) {
277
			$payload->setType(Payload::RELEASE_CREATE_FAIL);
278
			$payload->setMessage('empty release name');
279
			$payload->setCode(255);
280
			return $payload;
281
		}
282
283
		if (!strlen($path)) {
284
			$payload->setType(Payload::RELEASE_CREATE_FAIL);
285
			$payload->setMessage('empty path');
286
			$payload->setCode(255);
287
			return $payload;
288
		}
289
290
		$path = $this->absolutePath($path, getcwd());
291
292
		$releaseDir = realpath($path) . DIRECTORY_SEPARATOR . 'releases' . DIRECTORY_SEPARATOR . $release;
293
294
		if (!mkdir($releaseDir, 0777, true)) {
295
			$payload->setType(Payload::RELEASE_CREATE_FAIL);
296
			$payload->setMessage('release "' . $release . '" does not created');
297
			$payload->setCode(255);
298
			return $payload;
299
		}
300
301
		$payload->setType(Payload::RELEASE_CREATE_SUCCESS);
302
		$payload->setMessage('release "' . $release . '" created');
303
		$payload->setCode(0);
304
		return $payload;
305
	}
306
307
	/**
308
	 * @param string $release
309
	 * @param string $path
310
	 * @return \Deploid\Payload
311
	 */
312
	public function deploidReleaseRemove($release, $path) {
313
		$payload = new Payload();
314
315
		if (!strlen($release)) {
316
			$payload->setType(Payload::RELEASE_REMOVE_FAIL);
317
			$payload->setMessage('empty release name');
318
			$payload->setCode(255);
319
			return $payload;
320
		}
321
322
		if (!strlen($path)) {
323
			$payload->setType(Payload::RELEASE_REMOVE_FAIL);
324
			$payload->setMessage('empty path');
325
			$payload->setCode(255);
326
			return $payload;
327
		}
328
329
		$path = $this->absolutePath($path, getcwd());
330
331
		$proccess = new Process('rm -r ' . realpath($path) . DIRECTORY_SEPARATOR . 'releases' . DIRECTORY_SEPARATOR . $release);
332
		$proccess->run();
333
334
		if (!$proccess->isSuccessful()) {
335
			$payload->setType(Payload::RELEASE_REMOVE_FAIL);
336
			$payload->setMessage($proccess->getErrorOutput());
337
			$payload->setCode($proccess->getExitCode());
338
			return $payload;
339
		}
340
341
		$payload->setType(Payload::RELEASE_REMOVE_SUCCESS);
342
		$payload->setMessage('release "' . ($release == '*' ? 'all' : $release) . '" removed');
343
		$payload->setCode(0);
344
		return $payload;
345
	}
346
347
	/**
348
	 * @param string $path
349
	 * @return \Deploid\Payload
350
	 */
351
	public function deploidReleaseList($path) {
352
		$payload = new Payload();
353
354
		if (!strlen($path)) {
355
			$payload->setType(Payload::RELEASE_LIST_FAIL);
356
			$payload->setMessage('path "' . $path . '" invalid');
357
			$payload->setCode(255);
358
			return $payload;
359
		}
360
361
		$path = $this->absolutePath($path, getcwd());
362
363
		$dirs = glob(realpath($path) . DIRECTORY_SEPARATOR . 'releases' . DIRECTORY_SEPARATOR . '*', GLOB_ONLYDIR);
364
365
		if (empty($dirs)) {
366
			$payload->setType(Payload::RELEASE_LIST_FAIL);
367
			$payload->setMessage('release not found');
368
			$payload->setCode(0);
369
			return $payload;
370
		}
371
372
		$dirs = array_map(function ($path) {
373
			return basename($path);
374
		}, $dirs);
375
376
		$payload->setType(Payload::RELEASE_LIST_SUCCESS);
377
		$payload->setMessage($dirs);
378
		$payload->setCode(0);
379
		return $payload;
380
	}
381
382
	/**
383
	 * @param string $path
384
	 * @return \Deploid\Payload
385
	 */
386
	public function deploidReleaseLatest($path) {
387
		$payload = new Payload();
388
389
		if (!strlen($path)) {
390
			$payload->setType(Payload::RELEASE_LATEST_FAIL);
391
			$payload->setMessage('empty path');
392
			$payload->setCode(255);
393
			return $payload;
394
		}
395
396
		$path = $this->absolutePath($path, getcwd());
397
398
		$dirs = glob(realpath($path) . DIRECTORY_SEPARATOR . 'releases' . DIRECTORY_SEPARATOR . '*', GLOB_ONLYDIR);
399
400
		if (empty($dirs)) {
401
			$payload->setType(Payload::RELEASE_LATEST_FAIL);
402
			$payload->setMessage('release not found');
403
			$payload->setCode(255);
404
			return $payload;
405
		}
406
407
		$dirs = array_map(function ($path) {
408
			return basename($path);
409
		}, $dirs);
410
411
		if (!rsort($dirs)) {
412
			$payload->setType(Payload::RELEASE_LATEST_FAIL);
413
			$payload->setMessage('fail sorted');
414
			$payload->setCode(255);
415
			return $payload;
416
		}
417
418
		$payload->setType(Payload::RELEASE_LATEST_SUCCESS);
419
		$payload->setMessage(current($dirs));
420
		$payload->setCode(0);
421
		return $payload;
422
	}
423
424
	/**
425
	 * @param string $path
426
	 * @return \Deploid\Payload
427
	 */
428
	public function deploidReleaseCurrent($path) {
429
		$payload = new Payload();
430
431
		if (!strlen($path)) {
432
			$payload->setType(Payload::RELEASE_CURRENT_FAIL);
433
			$payload->setMessage('empty path');
434
			$payload->setCode(255);
435
			return $payload;
436
		}
437
438
		$path = $this->absolutePath($path, getcwd());
439
440
		$link = realpath($path) . DIRECTORY_SEPARATOR . 'current';
441
442
		if (!file_exists($link)) {
443
			$payload->setType(Payload::RELEASE_CURRENT_FAIL);
444
			$payload->setMessage('current release does not exist');
445
			$payload->setCode(255);
446
			return $payload;
447
		}
448
449
		if (!is_link($link)) {
450
			$payload->setType(Payload::RELEASE_CURRENT_FAIL);
451
			$payload->setMessage('link to current release does not exist');
452
			$payload->setCode(255);
453
			return $payload;
454
		}
455
456
		$linkpath = readlink($link);
457
458
		if (!$linkpath) {
459
			$payload->setType(Payload::RELEASE_CURRENT_FAIL);
460
			$payload->setMessage('fail read link to current release');
461
			$payload->setCode(255);
462
			return $payload;
463
		}
464
465
		$payload->setType(Payload::RELEASE_CURRENT_SUCCESS);
466
		$payload->setMessage(basename($linkpath));
467
		$payload->setCode(0);
468
		return $payload;
469
	}
470
471
	/**
472
	 * @param string $release
473
	 * @param string $path
474
	 * @return \Deploid\Payload
475
	 */
476
	public function deploidReleaseSetup($release, $path) {
477
		$payload = new Payload();
478
479
		if (!strlen($path)) {
480
			$payload->setType(Payload::RELEASE_SETUP_FAIL);
481
			$payload->setMessage('path "' . $path . '" invalid');
482
			$payload->setCode(255);
483
			return $payload;
484
		}
485
486
		$path = $this->absolutePath($path, getcwd());
487
488
		$releaseDir = realpath($path) . DIRECTORY_SEPARATOR . 'releases' . DIRECTORY_SEPARATOR . $release;
489
		$currentDir = realpath($path) . DIRECTORY_SEPARATOR . 'current';
490
491
		$proccess = new Process('ln -sfn ' . $releaseDir . ' ' . $currentDir);
492
		$proccess->run();
493
494
		if (!$proccess->isSuccessful()) {
495
			$payload->setType(Payload::RELEASE_SETUP_FAIL);
496
			$payload->setMessage($proccess->getErrorOutput());
497
			$payload->setCode($proccess->getExitCode());
498
			return $payload;
499
		}
500
501
		$payload->setType(Payload::RELEASE_SETUP_SUCCESS);
502
		$payload->setMessage('release "' . $release . '" setup');
503
		$payload->setCode(0);
504
		return $payload;
505
	}
506
507
	/**
508
	 * @param int $quantity
509
	 * @param string $path
510
	 * @return \Deploid\Payload
511
	 */
512
	public function deploidReleaseRotate($quantity, $path) {
513
		$payload = new Payload();
514
515
		if (!$quantity || $quantity < 1) {
516
			$payload->setType(Payload::RELEASE_ROTATE_FAIL);
517
			$payload->setMessage('empty or invalid quantity');
518
			$payload->setCode(255);
519
			return $payload;
520
		}
521
522
		if (!strlen($path)) {
523
			$payload->setType(Payload::RELEASE_ROTATE_FAIL);
524
			$payload->setMessage('empty path');
525
			$payload->setCode(255);
526
			return $payload;
527
		}
528
529
		$path = $this->absolutePath($path, getcwd());
530
531
		$releases = glob(realpath($path) . DIRECTORY_SEPARATOR . 'releases' . DIRECTORY_SEPARATOR . '*', GLOB_ONLYDIR);
532
533
		if (count($releases) <= $quantity) {
534
			$payload->setType(Payload::RELEASE_ROTATE_SUCCESS);
535
			$payload->setMessage('not found releases to rotate');
536
			$payload->setCode(0);
537
		}
538
539
		foreach (array_reverse($releases) as $idx => $release) {
540
			if ($idx <= ($quantity - 1)) continue;
541
			$proccess = new Process('rm -r ' . $release);
542
			$proccess->run();
543
		}
544
545
		$payload->setType(Payload::RELEASE_ROTATE_SUCCESS);
546
		$payload->setMessage('releases are rotated');
547
		$payload->setCode(0);
548
		return $payload;
549
	}
550
551
	public function absolutePath($path, $cwd) {
552
		if (empty($path)) throw new \InvalidArgumentException('empty path');
553
		if (empty($cwd)) throw new \InvalidArgumentException('empty cwd');
554
555
		if ($path[0] == '/') return $path;
556
557
		return $cwd . DIRECTORY_SEPARATOR . $path;
558
	}
559
560
}