Completed
Pull Request — master (#3)
by Harry
07:29
created

MergeFiles::runCommand()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 29
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 29
ccs 14
cts 14
cp 1
rs 8.439
cc 6
eloc 17
nc 6
nop 4
crap 6
1
<?php
2
/**
3
 * This file is part of graze/data-file
4
 *
5
 * Copyright (c) 2016 Nature Delivered Ltd. <https://www.graze.com>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @license https://github.com/graze/data-file/blob/master/LICENSE.md
11
 * @link    https://github.com/graze/data-file
12
 */
13
14
namespace Graze\DataFile\Modify\Contract;
15
16
use DirectoryIterator;
17
use Graze\DataFile\Helper\GetOptionTrait;
18
use Graze\DataFile\Helper\OptionalLoggerTrait;
19
use Graze\DataFile\Helper\Process\ProcessFactoryAwareInterface;
20
use Graze\DataFile\Helper\Process\ProcessTrait;
21
use Graze\DataFile\Modify\Compress\CompressionFactory;
22
use Graze\DataFile\Modify\MakeDirectory;
23
use Graze\DataFile\Node\FileNode;
24
use Graze\DataFile\Node\FileNodeCollectionInterface;
25
use Graze\DataFile\Node\FileNodeInterface;
26
use Graze\DataFile\Node\LocalFile;
27
use Psr\Log\LoggerAwareInterface;
28
use Psr\Log\LogLevel;
29
use Symfony\Component\Process\Exception\ProcessFailedException;
30
31
class MergeFiles implements FileContractorInterface, LoggerAwareInterface, ProcessFactoryAwareInterface
32 11
{
33
    use GetOptionTrait;
34 11
    use OptionalLoggerTrait;
35 1
    use ProcessTrait;
36
37
    /**
38 10
     * @param FileNodeCollectionInterface $files
39 9
     * @param FileNodeInterface           $target
40 9
     *
41 8
     * @return bool
42 9
     */
43 4
    public function canContract(FileNodeCollectionInterface $files, FileNodeInterface $target)
44
    {
45 9
        if (!($target instanceof LocalFile)) {
46 9
            return false;
47
        }
48
49
        foreach ($files->getIterator() as $file) {
50
            if (!($file instanceof LocalFile) ||
51
                !($file->exists()) ||
52
                ($file->getCompression() != CompressionFactory::TYPE_NONE)
53
            ) {
54
                return false;
55
            }
56
        }
57
        return true;
58 7
    }
59
60
    /**
61
     * Do the expansion and return a collection
62
     *
63 7
     * @param FileNodeCollectionInterface $files
64 7
     * @param FileNodeInterface           $target
65 2
     * @param array                       $options :keepOldFiles <bool> (Default: true) Keep the old files after merging
66
     *
67
     * @return FileNodeInterface
68 5
     */
69
    public function contract(
70
        FileNodeCollectionInterface $files,
71 5
        FileNodeInterface $target,
72 5
        array $options = []
73
    ) {
74 5
        $this->options = $options;
75 5
        if (!$this->canContract($files, $target)) {
76 5
            throw new \InvalidArgumentException("The supplied files are not valid");
77 5
        }
78 5
79
        $this->log(LogLevel::INFO, "Merging files in collection $files into: {$target}");
80 5
81
        $filePaths = $files->map(function (LocalFile $item) {
82
            return $item->getPath();
83
        });
84
85
        $cmd = sprintf(
86
            'cat %s > %s',
87
            implode(' ', $filePaths),
88
            $target->getPath()
89
        );
90
91
        return $this->runCommand($files, $target, $cmd, $this->getOption('keepOldFiles', true));
92 5
    }
93
94 5
    /**
95 5
     * @param FileNodeCollectionInterface $files
96 5
     * @param FileNodeInterface           $target
97 5
     * @param string                      $cmd
98
     * @param bool                        $keepOld
99 5
     *
100 5
     * @return FileNodeInterface
101
     * @throws \Graze\DataFile\Modify\Exception\MakeDirectoryFailedException
102 5
     */
103 1
    private function runCommand(FileNodeCollectionInterface $files, FileNodeInterface $target, $cmd, $keepOld = true)
104
    {
105
        if ($target instanceof FileNode) {
106 4
            $maker = new MakeDirectory();
107 2
            $maker->makeDirectory($target);
108 2
        }
109 2
110 2
        $process = $this->getProcess($cmd);
111 2
        $process->run();
112 2
113 2
        if (!$process->isSuccessful()) {
114 2
            throw new ProcessFailedException($process);
115 2
        }
116 2
117 2
        if (!$keepOld) {
118
            $this->log(LogLevel::DEBUG, "Deleting old files in collection $files");
119 4
            $files->map(function (LocalFile $item) {
120
                if ($item->exists()) {
121
                    $item->delete();
122
                }
123
                $count = iterator_count(new DirectoryIterator($item->getDirectory()));
124
                if ($count == 2) {
125
                    rmdir($item->getDirectory());
126
                }
127
            });
128
        }
129
130
        return $target;
131
    }
132
}
133