Failed Conditions
Pull Request — master (#14)
by
unknown
05:17
created

DownloadCommand::getFilesByTypeAndVersion()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 11
Code Lines 6

Duplication

Lines 11
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 11
loc 11
rs 9.2
cc 4
eloc 6
nc 3
nop 2
1
<?php
2
/**
3
 * Magedownload CLI
4
 *
5
 * PHP version 5
6
 *
7
 * @category  MageDownload
8
 * @package   MageDownload
9
 * @author    Steve Robbins <[email protected]>
10
 * @copyright 2015 Steve Robbins
11
 * @license   http://creativecommons.org/licenses/by/4.0/ CC BY 4.0
12
 * @link      https://github.com/steverobbins/magedownload-cli
13
 */
14
15
namespace MageDownload\Command;
16
17
use MageDownload\Download;
18
use MageDownload\Info;
19
use Symfony\Component\Console\Input\InputArgument;
20
use Symfony\Component\Console\Input\InputInterface;
21
use Symfony\Component\Console\Input\InputOption;
22
use Symfony\Component\Console\Output\OutputInterface;
23
use ZipArchive;
24
25
/**
26
 * Download file command
27
 *
28
 * @category  MageDownload
29
 * @package   MageDownload
30
 * @author    Steve Robbins <[email protected]>
31
 * @copyright 2015 Steve Robbins
32
 * @license   http://creativecommons.org/licenses/by/4.0/ CC BY 4.0
33
 * @link      https://github.com/steverobbins/magedownload-cli
34
 */
35
class DownloadCommand extends AbstractCommand
36
{
37
    const NAME = 'download';
38
39
    const ARGUMENT_NAME        = 'name';
40
    const ARGUMENT_DESTINATION = 'destination';
41
42
    const OPTION_EXTRACT = 'extract';
43
44
    protected $downloads;
45
46
    /**
47
     * Interactively select a file to download
48
     *
49
     * @param InputInterface  $input
50
     * @param OutputInterface $output
51
     *
52
     * @return void
53
     */
54
    protected function interact(InputInterface $input, OutputInterface $output)
55
    {
56
        if (!$input->getArgument(self::ARGUMENT_NAME)) {
57
            $info = new Info;
58
            $action = 'filter/version/*';
59
60
            $result = $info->sendCommand(
61
                $action,
62
                $this->getAccountId(),
63
                $this->getAccessToken()
64
            );
65
66
            $bits = preg_split('/\-{5,}/', $result);
67
            if (count($bits) == 1) {
68
                return $this->out(trim($result));
69
            }
70
            $headers = array();
71
            foreach (preg_split('/ {2,}/', $bits[0]) as $value) {
72
                $headers[] = trim($value);
73
            }
74
            $rows = array();
75 View Code Duplication
            foreach (explode("\n", $bits[1]) as $row) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
76
                if (empty($row)) {
77
                    continue;
78
                }
79
                $row = preg_split('/ {2,}/', $row);
80
                $rows[] = array_combine($headers, $row);
81
            }
82
            $this->downloads = $rows;
83
84
            $dialog = $this->getHelper('dialog');
85
            $selectedMsg = 'You have just selected: <info>%s</info>' . PHP_EOL;
86
87
            $types = $this->getTypes();
88
            $type = $dialog->select(
89
                $this->output,
90
                '<question>Choose a type of download:</question>',
91
                $types,
92
                0
93
            );
94
            $type = $types[$type];
95
            $this->output->writeln(sprintf($selectedMsg, $type));
96
97
            $versions = $this->getVersionsByType($type);
98
            $version = $dialog->select(
99
                $this->output,
100
                '<question>Choose a version:</question>',
101
                $versions,
102
                0
103
            );
104
            $version = $versions[$version];
105
            $this->output->writeln(sprintf($selectedMsg, $version));
106
107
            $files = $this->getFilesByTypeAndVersion($type, $version);
108
            $file = $dialog->select(
109
                $this->output,
110
                '<question>Choose a file:</question>',
111
                $files,
112
                0
113
            );
114
            $file = $files[$file];
115
            $this->output->writeln(sprintf($selectedMsg, $file));
116
117
            $this->input->setArgument(self::ARGUMENT_NAME, $file);
118
        }
119
    }
120
121
    /**
122
     * Configure command
123
     *
124
     * @return void
125
     */
126
    protected function configure()
127
    {
128
        $this
129
            ->setName(self::NAME)
130
            ->setDescription('Download a release or patch')
131
            ->addArgument(
132
                self::ARGUMENT_NAME,
133
                InputArgument::REQUIRED,
134
                'The name of the file to download'
135
            )
136
            ->addArgument(
137
                self::ARGUMENT_DESTINATION,
138
                InputArgument::OPTIONAL,
139
                'The destination where the file should be downloaded'
140
            )
141
            ->addOption(
142
                self::OPTION_EXTRACT,
143
                'x',
144
                InputOption::VALUE_NONE,
145
                'When given, the downloaded file will be extracted if possible'
146
            );
147
        parent::configure();
148
    }
149
150
    /**
151
     * Execute command
152
     *
153
     * @param InputInterface  $input
154
     * @param OutputInterface $output
155
     *
156
     * @return void
157
     */
158
    protected function execute(InputInterface $input, OutputInterface $output)
159
    {
160
        $destination = $this->getDestination();
161
        $this->output->writeln(sprintf('Downloading to <info>%s</info>...', $destination));
162
        $download = new Download;
163
        $result = $download->get(
164
            $this->input->getArgument(self::ARGUMENT_NAME),
165
            $this->getAccountId(),
166
            $this->getAccessToken()
167
        );
168
        $success = file_put_contents($destination, $result);
169
        if (!$success) {
170
            return $this->output->writeln('<error>Failed to download file</error>');
171
        }
172
        if ($input->getOption(self::OPTION_EXTRACT)) {
173
            $this->extract($destination, $output);
174
        }
175
        $this->output->writeln('Complete');
176
    }
177
178
    /**
179
     * Extract the downloaded file
180
     *
181
     * @param string          $file
182
     * @param OutputInterface $output
183
     *
184
     * @return void
185
     */
186
    protected function extract($file, OutputInterface $output)
187
    {
188
        if (substr($file, -8) === '.tar.bz2' || substr($file, -7) === '.tar.gz') {
189
            $destination = substr($file, -8) === '.tar.bz2' ? substr($file, 0, -8) : substr($file, 0, -7);
190
            $output->writeln(sprintf('Extracting to <info>%s</info>...', $destination));
191
            if (!is_dir($destination)) {
192
                mkdir($destination, 0777, true);
193
            }
194
            exec("tar -xf $file -C $destination");
195
        } elseif (substr($file, -4) === '.zip') {
196
            $destination = substr($file, 0, -4);
197
            $output->writeln(sprintf('Extracting to <info>%s</info>...', $destination));
198
            $zip = new ZipArchive();
199
            if ($zip->open($file) === true) {
200
                $zip->extractTo($destination);
201
                $zip->close();
202
            }
203
        } else {
204
            return;
205
        }
206
        if (is_dir($destination)) {
207
            unlink($file);
208
            if (is_dir($mageDir = $destination . DIRECTORY_SEPARATOR . 'magento')) {
209
                $tmp = 'magedownload_' . microtime(true);
210
                exec("mv $mageDir /tmp/$tmp && rm -rf $destination && mv /tmp/$tmp $destination");
211
            }
212
            return;
213
        }
214
        $output->writeln('<error>Failed to extract contents</error>');
215
    }
216
217
    /**
218
     * Determine where the file should download to
219
     *
220
     * @return string
221
     */
222
    private function getDestination()
223
    {
224
        $dest = $this->input->getArgument(self::ARGUMENT_DESTINATION);
225
        if (!$dest) {
226
            return getcwd() . DIRECTORY_SEPARATOR . $this->input->getArgument(self::ARGUMENT_NAME);
227
        }
228
        if (is_dir($dest)) {
229
            if (substr($dest, -1) !== '/') {
230
                $dest .= DIRECTORY_SEPARATOR;
231
            }
232
            return $dest . $this->input->getArgument(self::ARGUMENT_NAME);
233
        }
234
        return $dest;
235
    }
236
237
    protected function getTypes()
238
    {
239
        $matches = array();
240
        foreach ($this->downloads as $download) {
241
            $matches[] = $download['File Type'];
242
        }
243
244
        return array_values(array_unique($matches));
245
    }
246
247 View Code Duplication
    protected function getVersionsByType($type)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
248
    {
249
        $matches = array();
250
        foreach ($this->downloads as $download) {
251
            if ($download['File Type'] === $type) {
252
                $matches[] = $download['Version'];
253
            }
254
        }
255
256
        return array_values(array_unique($matches));
257
    }
258
259 View Code Duplication
    protected function getFilesByTypeAndVersion($type, $version)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
260
    {
261
        $matches = array();
262
        foreach ($this->downloads as $download) {
263
            if ($download['File Type'] === $type && $download['Version'] === $version) {
264
                $matches[] = $download['File Name'];
265
            }
266
        }
267
268
        return array_values(array_unique($matches));
269
    }
270
}
271