Failed Conditions
Pull Request — master (#15)
by Steve
03:42
created

DownloadCommand   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 226
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 6
Bugs 0 Features 2
Metric Value
wmc 23
c 6
b 0
f 2
lcom 1
cbo 6
dl 0
loc 226
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A interact() 0 52 2
A configure() 0 23 1
A execute() 0 19 3
D extract() 0 30 9
A getDestination() 0 14 4
A prepareDownloads() 0 13 4
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
    /**
45
     * Organized files that can be downloaded
46
     *
47
     * I.e. array(
48
     *     'Community Edition - Full' => array(
49
     *         '1.9.1.1' => array(
50
     *             '1.9.1.1.tar.bz2',
51
     *             '1.9.1.1.tar.gz',
52
     *             '1.9.1.1.zip',
53
     *         ),
54
     *         ...
55
     *     ),
56
     *     ...
57
     * )
58
     *
59
     * @var array
60
     */
61
    protected $downloads;
62
63
    /**
64
     * Interactively select a file to download
65
     *
66
     * @param InputInterface  $input
67
     * @param OutputInterface $output
68
     *
69
     * @return void
70
     */
71
    protected function interact(InputInterface $input, OutputInterface $output)
72
    {
73
        if (!$input->getArgument(self::ARGUMENT_NAME)) {
74
            $info = new Info;
75
            $this->prepareDownloads($info->sendCommand(
1 ignored issue
show
Bug introduced by
It seems like $info->sendCommand('filt...getAccessToken(), true) targeting MageDownload\Info::sendCommand() can also be of type string; however, MageDownload\Command\Dow...and::prepareDownloads() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

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