DownloadCommand   A
last analyzed

Complexity

Total Complexity 23

Size/Duplication

Total Lines 226
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 5

Importance

Changes 0
Metric Value
wmc 23
lcom 2
cbo 5
dl 0
loc 226
rs 10
c 0
b 0
f 0

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(
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