Issues (25)

src/Application.php (3 issues)

Labels
Severity
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 string */
16
	private $chmod = 0777;
17
18
	/** @var array */
19
	private $structure = [
20
		'dirs' => [
21
			'releases',
22
			'releases/first',
23
			'shared',
24
		],
25
		'files' => [
26
			'deploid.log',
27
		],
28
		'links' => [
29
			'current:releases/first',
30
		],
31
	];
32
33
	/** @var LoggerInterface */
34
	private $logger;
35
36
	/* mutators */
37
38
	public function getReleaseNameFormat() {
39
		return $this->releaseNameFormat;
40
	}
41
42
	public function setReleaseNameFormat($releaseNameFormat) {
43
		$this->releaseNameFormat = $releaseNameFormat;
44
	}
45
46
	public function getChmod() {
47
		return $this->chmod;
48
	}
49
50
	public function setChmod($chmod) {
51
		$this->chmod = $chmod;
52
	}
53
54
	/**
55
	 * @return LoggerInterface
56
	 */
57
	public function getLogger() {
58
		return $this->logger;
59
	}
60
61
	/**
62
	 * @param LoggerInterface $logger
63
	 * @return void
64
	 */
65
	public function setLogger(LoggerInterface $logger) {
66
		$this->logger = $logger;
67
	}
68
69
	public function getStructure() {
70
		return $this->structure;
71
	}
72
73
	public function setStructure(array $structure) {
74
		$this->structure = $structure;
75
	}
76
77 1
	public function makeStructure($path, array $structure) {
78 1
		if (empty($path)) throw new \InvalidArgumentException('empty path');
79
80 1
		if (empty($structure)) true;
81
82 1
		foreach ($structure as $section => $items) {
83 1
			if (empty($items)) continue;
84 1
			foreach ($items as $item) {
85 1
				if (empty($item)) continue;
86 1
				if ($section == 'dirs') {
87 1
					$dir = $path . DIRECTORY_SEPARATOR . $item;
88 1
					mkdir($dir, $this->chmod, true);
0 ignored issues
show
$this->chmod of type string is incompatible with the type integer expected by parameter $mode of mkdir(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

88
					mkdir($dir, /** @scrutinizer ignore-type */ $this->chmod, true);
Loading history...
89 1
				} else if ($section == 'files') {
90 1
					$file = $path . DIRECTORY_SEPARATOR . $item;
91 1
					if (!is_dir(dirname($file))) mkdir(dirname($file), $this->chmod, true);
92 1
					touch($path . DIRECTORY_SEPARATOR . $item);
93 1
				} else if ($section == 'links') {
94 1
					$link = $path . DIRECTORY_SEPARATOR . (explode(':', $item)[0]);
95 1
					$target = $path . DIRECTORY_SEPARATOR . (explode(':', $item)[1]);
96 1
					if (!is_dir(dirname($link))) mkdir(dirname($link), $this->chmod, true);
97 1
					symlink($target, $link);
98 1
				}
99 1
			}
100 1
		}
101
102 1
		return true;
103
	}
104
105
	public function scanStructure($path) {
106
		if (empty($path)) throw new \InvalidArgumentException('empty path');
107
108
		$directory = new \RecursiveDirectoryIterator(realpath($path), \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS);
109
		$iterator = new \RecursiveIteratorIterator($directory, \RecursiveIteratorIterator::SELF_FIRST);
110
111
		$items = [];
112
		foreach ($iterator as $item) {
113
			$items[] = $item;
114
		}
115
116
		if (empty($items)) return [];
117
118
		$structure = [];
119
		foreach ($items as $item) {
120
			if (is_link($item)) {
121
				$structure['links'][] = str_ireplace(realpath($path) . DIRECTORY_SEPARATOR, '', $item) . ':' . str_ireplace(realpath($path) . DIRECTORY_SEPARATOR, '', readlink($item));
122
			} else if (is_file($item)) {
123
				$structure['files'][] = str_ireplace(realpath($path) . DIRECTORY_SEPARATOR, '', $item);
124
			} else if (is_dir($item)) {
125
				$structure['dirs'][] = str_ireplace(realpath($path) . DIRECTORY_SEPARATOR, '', $item);
126
			}
127
		}
128
129
		return $structure;
130
	}
131
132
	public function sortStructure(array $structure) {
133
		ksort($structure);
134
135
		$structure = array_map(function ($item) {
136
			sort($item);
137
			return $item;
138
		}, $structure);
139
140
		return $structure;
141
	}
142
143
	public function diffStructure(array $structureThin, array $structureFat) {
144
		if (empty($structureThin)) return [];
145
		if (empty($structureFat)) return [];
146
147
		$structureDiff = [];
148
149
		foreach ($structureFat as $section => $items) {
150
			if (empty($structureThin[$section])) continue;
151
			$diff = array_diff($items, $structureThin[$section]);
152
			if (empty($diff)) continue;
153
			$structureDiff[$section] = $diff;
154
		}
155
156
		return $structureDiff;
157
	}
158
159
	public function toRealpaths($path, array $structure) {
160
		if (empty($path)) throw new \InvalidArgumentException('empty path');
161
162
		if (empty($structure)) return [];
163
164
		$realpaths = [];
165
166
		foreach ($structure as $section => $items) {
167
			if (empty($items)) continue;
168
			foreach ($items as $item) {
169
				if (empty($item)) continue;
170
				if ($section == 'links') {
171
					$realpaths[] = realpath($path) . DIRECTORY_SEPARATOR . explode(':', $item)[0];
172
				} else if ($section == 'files') {
173
					$realpaths[] = realpath($path) . DIRECTORY_SEPARATOR . $item;
174
				} else if ($section == 'dirs') {
175
					$realpaths[] = realpath($path) . DIRECTORY_SEPARATOR . $item;
176
				}
177
			}
178
		}
179
180
		rsort($realpaths);
181
182
		return $realpaths;
183
	}
184
185
	/* tools */
186
187
	/**
188
	 * @param string $path
189
	 * @return \Deploid\Payload
190
	 */
191 2
	public function deploidStructureValidate($path) {
192 2
		$payload = new Payload();
193
194 2
		if (!strlen($path)) {
195
			$payload->setType(Payload::STRUCTURE_VALIDATE_FAIL);
196
			$payload->setMessage('empty path');
197
			$payload->setCode(255);
198
			return $payload;
199
		}
200
201 2
		$path = $this->absolutePath($path, getcwd());
202 2
		$messages = [];
203
204 2
		foreach ($this->structure as $section => $items) {
205 2
			if (empty($items)) continue;
206 2
			foreach ($items as $item) {
207 2
				if (empty($item)) continue;
208 2
				if ($section == 'dirs') {
209 2
					$dir = $path . DIRECTORY_SEPARATOR . $item;
210 2
					if (!is_dir($dir)) $messages[] = 'directory "' . $dir . '" not found';
211 2
				} else if ($section == 'files') {
212 2
					$file = $path . DIRECTORY_SEPARATOR . $item;
213 2
					if (!is_file($file)) $messages[] = 'file "' . $file . '" not found';
214 2
				} else if ($section == 'links') {
215 2
					$link = $path . DIRECTORY_SEPARATOR . (explode(':', $item)[0]);
216 2
					if (!is_link($link)) $messages[] = 'link "' . realpath($link) . '" not found';
217 2
				}
218 2
			}
219 2
		}
220
221 2
		if (count($messages)) {
222 1
			$payload->setType(Payload::STRUCTURE_VALIDATE_FAIL);
223 1
			$payload->setMessage($messages);
224 1
			$payload->setCode(255);
225 1
			return $payload;
226
		}
227
228 1
		$payload->setType(Payload::STRUCTURE_VALIDATE_SUCCESS);
229 1
		$payload->setMessage('structure is valid');
230 1
		$payload->setCode(0);
231 1
		return $payload;
232
	}
233
234
	/**
235
	 * @param string $path
236
	 * @return \Deploid\Payload
237
	 */
238 1
	public function deploidStructureInit($path) {
239 1
		$payload = new Payload();
240
241 1
		if (!strlen($path)) {
242
			$payload->setType(Payload::STRUCTURE_INIT_FAIL);
243
			$payload->setMessage('empty path');
244
			$payload->setCode(255);
245
			return $payload;
246
		}
247
248 1
		$path = $this->absolutePath($path, getcwd());
249 1
		$messages = [];
250
251 1
		if (!is_dir($path)) {
252
			if (mkdir($path, $this->chmod, true)) {
0 ignored issues
show
$this->chmod of type string is incompatible with the type integer expected by parameter $mode of mkdir(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

252
			if (mkdir($path, /** @scrutinizer ignore-type */ $this->chmod, true)) {
Loading history...
253
				$messages[] = 'directory "' . realpath($path) . '" created';
254
			} else {
255
				$payload->setType(Payload::STRUCTURE_INIT_FAIL);
256
				$payload->setMessage('directory "' . $path . '" does not created');
257
				$payload->setCode(255);
258
				return $payload;
259
			}
260
		}
261
262 1
		foreach ($this->structure as $section => $items) {
263 1
			if (empty($items)) continue;
264 1
			foreach ($items as $item) {
265 1
				if (empty($item)) continue;
266 1
				if ($section == 'dirs') {
267 1
					$dir = $path . DIRECTORY_SEPARATOR . $item;
268 1
					if (mkdir($dir, $this->chmod, true)) {
269 1
						$messages[] = 'directory "' . $dir . '" created';
270 1
					} else {
271
						$payload->setType(Payload::STRUCTURE_INIT_FAIL);
272
						$payload->setMessage('directory "' . $dir . '" does not created');
273
						$payload->setCode(255);
274
						return $payload;
275
					}
276 1
				} else if ($section == 'files') {
277 1
					$file = $path . DIRECTORY_SEPARATOR . $item;
278 1
					if (touch($file)) {
279 1
						$messages[] = 'file "' . $file . '" created';
280 1
					} else {
281
						$payload->setType(Payload::STRUCTURE_INIT_FAIL);
282
						$payload->setMessage('file"' . $file . '" does not created');
283
						$payload->setCode(255);
284
						return $payload;
285
					}
286 1
				} else if ($section == 'links') {
287 1
					$target = $path . DIRECTORY_SEPARATOR . (explode(':', $item)[1]);
288 1
					$link = $path . DIRECTORY_SEPARATOR . (explode(':', $item)[0]);
289 1
					if (symlink($target, $link)) {
290 1
						$messages[] = 'link "' . $link . '" created';
291 1
					} else {
292
						$payload->setType(Payload::STRUCTURE_INIT_FAIL);
293
						$payload->setMessage('link ' . $link . '" does not created');
294
						$payload->setCode(255);
295
						return $payload;
296
					}
297 1
				}
298 1
			}
299 1
		}
300
301 1
		$payload->setType(Payload::STRUCTURE_INIT_SUCCESS);
302 1
		$payload->setMessage($messages);
303 1
		$payload->setCode(0);
304 1
		return $payload;
305
	}
306
307
	/**
308
	 * @param string $path
309
	 * @return \Deploid\Payload
310
	 */
311 1
	public function deploidStructureClean($path) {
312 1
		$payload = new Payload();
313
314 1
		if (!strlen($path)) {
315
			$payload->setType(Payload::STRUCTURE_CLEAN_FAIL);
316
			$payload->setMessage('empty path');
317
			$payload->setCode(255);
318
			return $payload;
319
		}
320
321 1
		$realpathsClean = $this->toRealpaths($path, $this->structure);
322 1
		$realpathsDirty = $this->toRealpaths($path, $this->scanStructure($path));
323 1
		$realpathsDiff = array_diff($realpathsDirty, $realpathsClean);
324
325 1
		foreach ($realpathsDiff as $item) {
326 1
			if (empty($item)) continue;
327 1
			if (is_link($item)) unlink($item);
328 1
			if (is_file($item)) unlink($item);
329 1
			if (is_dir($item)) rmdir($item);
330 1
		}
331
332 1
		$payload->setType(Payload::STRUCTURE_CLEAN_SUCCESS);
333 1
		$payload->setMessage(array_merge(['cleaned items:'], $realpathsDiff));
334 1
		$payload->setCode(0);
335 1
		return $payload;
336
	}
337
338
	/**
339
	 * @param string $release
340
	 * @param string $path
341
	 * @return \Deploid\Payload
342
	 */
343 2
	public function deploidReleaseExist($release, $path) {
344 2
		$payload = new Payload();
345
346 2
		if (!strlen($release)) {
347
			$payload->setType(Payload::RELEASE_EXIST_FAIL);
348
			$payload->setMessage('empty release name');
349
			$payload->setCode(255);
350
			return $payload;
351
		}
352
353 2
		if (!strlen($path)) {
354
			$payload->setType(Payload::RELEASE_EXIST_FAIL);
355
			$payload->setMessage('empty path');
356
			$payload->setCode(255);
357
			return $payload;
358
		}
359
360 2
		$path = $this->absolutePath($path, getcwd());
361
362 2
		$releaseDir = $path . DIRECTORY_SEPARATOR . 'releases' . DIRECTORY_SEPARATOR . $release;
363 2
		if (!is_dir($releaseDir)) {
364 1
			$payload->setType(Payload::RELEASE_EXIST_FAIL);
365 1
			$payload->setMessage('release "' . $release . '" does not exist');
366 1
			$payload->setCode(255);
367 1
			return $payload;
368
		}
369
370 1
		$payload->setType(Payload::RELEASE_EXIST_SUCCESS);
371 1
		$payload->setMessage('release "' . $release . '" exist');
372 1
		$payload->setCode(0);
373 1
		return $payload;
374
	}
375
376
	/**
377
	 * @param string $release
378
	 * @param string $path
379
	 * @return \Deploid\Payload
380
	 */
381 1
	public function deploidReleaseCreate($release, $path) {
382 1
		$payload = new Payload();
383
384 1
		if (!strlen($release)) {
385
			$payload->setType(Payload::RELEASE_CREATE_FAIL);
386
			$payload->setMessage('empty release name');
387
			$payload->setCode(255);
388
			return $payload;
389
		}
390
391 1
		if (!strlen($path)) {
392
			$payload->setType(Payload::RELEASE_CREATE_FAIL);
393
			$payload->setMessage('empty path');
394
			$payload->setCode(255);
395
			return $payload;
396
		}
397
398 1
		$path = $this->absolutePath($path, getcwd());
399
400 1
		$releaseDir = realpath($path) . DIRECTORY_SEPARATOR . 'releases' . DIRECTORY_SEPARATOR . $release;
401
402 1
		if (!mkdir($releaseDir, $this->chmod, true)) {
0 ignored issues
show
$this->chmod of type string is incompatible with the type integer expected by parameter $mode of mkdir(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

402
		if (!mkdir($releaseDir, /** @scrutinizer ignore-type */ $this->chmod, true)) {
Loading history...
403
			$payload->setType(Payload::RELEASE_CREATE_FAIL);
404
			$payload->setMessage('release "' . $release . '" does not created');
405
			$payload->setCode(255);
406
			return $payload;
407
		}
408
409 1
		$payload->setType(Payload::RELEASE_CREATE_SUCCESS);
410 1
		$payload->setMessage('release "' . $release . '" created');
411 1
		$payload->setCode(0);
412 1
		return $payload;
413
	}
414
415
	/**
416
	 * @param string $release
417
	 * @param string $path
418
	 * @return \Deploid\Payload
419
	 */
420 1
	public function deploidReleaseRemove($release, $path) {
421 1
		$payload = new Payload();
422
423 1
		if (!strlen($release)) {
424
			$payload->setType(Payload::RELEASE_REMOVE_FAIL);
425
			$payload->setMessage('empty release name');
426
			$payload->setCode(255);
427
			return $payload;
428
		}
429
430 1
		if (!strlen($path)) {
431
			$payload->setType(Payload::RELEASE_REMOVE_FAIL);
432
			$payload->setMessage('empty path');
433
			$payload->setCode(255);
434
			return $payload;
435
		}
436
437 1
		$path = $this->absolutePath($path, getcwd());
438
439 1
		$proccess = new Process('rm -r ' . realpath($path) . DIRECTORY_SEPARATOR . 'releases' . DIRECTORY_SEPARATOR . $release);
440 1
		$proccess->run();
441
442 1
		if (!$proccess->isSuccessful()) {
443
			$payload->setType(Payload::RELEASE_REMOVE_FAIL);
444
			$payload->setMessage($proccess->getErrorOutput());
445
			$payload->setCode($proccess->getExitCode());
446
			return $payload;
447
		}
448
449 1
		$payload->setType(Payload::RELEASE_REMOVE_SUCCESS);
450 1
		$payload->setMessage('release "' . ($release == '*' ? 'all' : $release) . '" removed');
451 1
		$payload->setCode(0);
452 1
		return $payload;
453
	}
454
455
	/**
456
	 * @param string $path
457
	 * @return \Deploid\Payload
458
	 */
459 1
	public function deploidReleaseList($path) {
460 1
		$payload = new Payload();
461
462 1
		if (!strlen($path)) {
463
			$payload->setType(Payload::RELEASE_LIST_FAIL);
464
			$payload->setMessage('path "' . $path . '" invalid');
465
			$payload->setCode(255);
466
			return $payload;
467
		}
468
469 1
		$path = $this->absolutePath($path, getcwd());
470
471 1
		$dirs = glob(realpath($path) . DIRECTORY_SEPARATOR . 'releases' . DIRECTORY_SEPARATOR . '*', GLOB_ONLYDIR);
472
473 1
		if (empty($dirs)) {
474
			$payload->setType(Payload::RELEASE_LIST_FAIL);
475
			$payload->setMessage('release not found');
476
			$payload->setCode(0);
477
			return $payload;
478
		}
479
480
		$dirs = array_map(function ($path) {
481 1
			return basename($path);
482 1
		}, $dirs);
483
484 1
		$payload->setType(Payload::RELEASE_LIST_SUCCESS);
485 1
		$payload->setMessage($dirs);
486 1
		$payload->setCode(0);
487 1
		return $payload;
488
	}
489
490
	/**
491
	 * @param string $path
492
	 * @return \Deploid\Payload
493
	 */
494 1
	public function deploidReleaseLatest($path) {
495 1
		$payload = new Payload();
496
497 1
		if (!strlen($path)) {
498
			$payload->setType(Payload::RELEASE_LATEST_FAIL);
499
			$payload->setMessage('empty path');
500
			$payload->setCode(255);
501
			return $payload;
502
		}
503
504 1
		$path = $this->absolutePath($path, getcwd());
505
506 1
		$dirs = glob(realpath($path) . DIRECTORY_SEPARATOR . 'releases' . DIRECTORY_SEPARATOR . '*', GLOB_ONLYDIR);
507
508 1
		if (empty($dirs)) {
509
			$payload->setType(Payload::RELEASE_LATEST_FAIL);
510
			$payload->setMessage('release not found');
511
			$payload->setCode(255);
512
			return $payload;
513
		}
514
515 1
		$dirs = array_map(function ($path) {
516 1
			return basename($path);
517 1
		}, $dirs);
518
519 1
		if (!rsort($dirs)) {
520
			$payload->setType(Payload::RELEASE_LATEST_FAIL);
521
			$payload->setMessage('fail sorted');
522
			$payload->setCode(255);
523
			return $payload;
524
		}
525
526 1
		$payload->setType(Payload::RELEASE_LATEST_SUCCESS);
527 1
		$payload->setMessage(current($dirs));
528 1
		$payload->setCode(0);
529 1
		return $payload;
530
	}
531
532
	/**
533
	 * @param string $path
534
	 * @return \Deploid\Payload
535
	 */
536 1
	public function deploidReleaseCurrent($path) {
537 1
		$payload = new Payload();
538
539 1
		if (!strlen($path)) {
540
			$payload->setType(Payload::RELEASE_CURRENT_FAIL);
541
			$payload->setMessage('empty path');
542
			$payload->setCode(255);
543
			return $payload;
544
		}
545
546 1
		$path = $this->absolutePath($path, getcwd());
547
548 1
		$link = realpath($path) . DIRECTORY_SEPARATOR . 'current';
549
550 1
		if (!file_exists($link)) {
551
			$payload->setType(Payload::RELEASE_CURRENT_FAIL);
552
			$payload->setMessage('current release does not exist');
553
			$payload->setCode(255);
554
			return $payload;
555
		}
556
557 1
		if (!is_link($link)) {
558
			$payload->setType(Payload::RELEASE_CURRENT_FAIL);
559
			$payload->setMessage('link to current release does not exist');
560
			$payload->setCode(255);
561
			return $payload;
562
		}
563
564 1
		$linkpath = readlink($link);
565
566 1
		if (!$linkpath) {
567
			$payload->setType(Payload::RELEASE_CURRENT_FAIL);
568
			$payload->setMessage('fail read link to current release');
569
			$payload->setCode(255);
570
			return $payload;
571
		}
572
573 1
		$payload->setType(Payload::RELEASE_CURRENT_SUCCESS);
574 1
		$payload->setMessage(basename($linkpath));
575 1
		$payload->setCode(0);
576 1
		return $payload;
577
	}
578
579
	/**
580
	 * @param string $release
581
	 * @param string $path
582
	 * @return \Deploid\Payload
583
	 */
584 1
	public function deploidReleaseSetup($release, $path) {
585 1
		$payload = new Payload();
586
587 1
		if (!strlen($path)) {
588
			$payload->setType(Payload::RELEASE_SETUP_FAIL);
589
			$payload->setMessage('path "' . $path . '" invalid');
590
			$payload->setCode(255);
591
			return $payload;
592
		}
593
594 1
		$path = $this->absolutePath($path, getcwd());
595
596 1
		$releaseDir = realpath($path) . DIRECTORY_SEPARATOR . 'releases' . DIRECTORY_SEPARATOR . $release;
597 1
		$currentDir = realpath($path) . DIRECTORY_SEPARATOR . 'current';
598
599 1
		$proccess = new Process('ln -sfn ' . $releaseDir . ' ' . $currentDir);
600 1
		$proccess->run();
601
602 1
		if (!$proccess->isSuccessful()) {
603
			$payload->setType(Payload::RELEASE_SETUP_FAIL);
604
			$payload->setMessage($proccess->getErrorOutput());
605
			$payload->setCode($proccess->getExitCode());
606
			return $payload;
607
		}
608
609 1
		$payload->setType(Payload::RELEASE_SETUP_SUCCESS);
610 1
		$payload->setMessage('release "' . $release . '" setup');
611 1
		$payload->setCode(0);
612 1
		return $payload;
613
	}
614
615
	/**
616
	 * @param int $quantity
617
	 * @param string $path
618
	 * @return \Deploid\Payload
619
	 */
620 1
	public function deploidReleaseRotate($quantity, $path) {
621 1
		$payload = new Payload();
622
623 1
		if (!$quantity || $quantity < 1) {
624
			$payload->setType(Payload::RELEASE_ROTATE_FAIL);
625
			$payload->setMessage('empty or invalid quantity');
626
			$payload->setCode(255);
627
			return $payload;
628
		}
629
630 1
		if (!strlen($path)) {
631
			$payload->setType(Payload::RELEASE_ROTATE_FAIL);
632
			$payload->setMessage('empty path');
633
			$payload->setCode(255);
634
			return $payload;
635
		}
636
637 1
		$path = $this->absolutePath($path, getcwd());
638
639 1
		$releases = glob(realpath($path) . DIRECTORY_SEPARATOR . 'releases' . DIRECTORY_SEPARATOR . '*', GLOB_ONLYDIR);
640
641 1
		if (count($releases) <= $quantity) {
642
			$payload->setType(Payload::RELEASE_ROTATE_SUCCESS);
643
			$payload->setMessage('not found releases to rotate');
644
			$payload->setCode(0);
645
		}
646
647 1
		foreach (array_reverse($releases) as $idx => $release) {
648 1
			if ($idx <= ($quantity - 1)) continue;
649 1
			$proccess = new Process('rm -r ' . $release);
650 1
			$proccess->run();
651 1
		}
652
653 1
		$payload->setType(Payload::RELEASE_ROTATE_SUCCESS);
654 1
		$payload->setMessage('releases are rotated');
655 1
		$payload->setCode(0);
656 1
		return $payload;
657
	}
658
659 2
	public function absolutePath($path, $cwd) {
660 2
		if (empty($path)) throw new \InvalidArgumentException('empty path');
661 2
		if (empty($cwd)) throw new \InvalidArgumentException('empty cwd');
662
663 2
		if ($path[0] == '/') return $path;
664
665 1
		return $cwd . DIRECTORY_SEPARATOR . $path;
666
	}
667
668
}