Skip to content

Commit ec55fb6

Browse files
committed
Case 27689; Updated db import commands to check existing files.
1 parent 5c47bbc commit ec55fb6

File tree

1 file changed

+114
-86
lines changed

1 file changed

+114
-86
lines changed

src/Command/SiteDbImportCommand.php

Lines changed: 114 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,12 @@ class SiteDbImportCommand extends SiteBaseCommand {
2929
*
3030
* @var
3131
*/
32-
protected $filename = NULL;
32+
protected $file = NULL;
33+
34+
/**
35+
* The temporary path to this db.
36+
*/
37+
protected $tmpFolder = '/tmp/';
3338

3439
/**
3540
* {@inheritdoc}
@@ -90,35 +95,25 @@ protected function execute(InputInterface $input, OutputInterface $output) {
9095
parent::execute($input, $output);
9196

9297
// Check if a dump file has been specified.
93-
if ($input->hasOption('file') &&
94-
!is_null($input->getOption('file'))
95-
) {
96-
$this->filename = $input->getOption('file');
98+
if ($input->hasOption('file') && !is_null($input->getOption('file'))) {
99+
$this->file = $input->getOption('file');
97100
}
101+
// Check if a dump file is set in the yaml config
98102
elseif (isset($this->config['db']['dump'])) {
99103
// Use config from sites.yml.
100-
$this->filename = $this->config['db']['dump'];
104+
$this->file = $this->config['db']['dump'];
101105
}
102106
else {
103107
throw new SiteCommandException('Please specify a file to import the dump from');
104108
}
105109

106-
// If the db dump is not local, download it locally.
107-
if (!stream_is_local($this->filename)) {
108-
$this->filename = $this->download($this->filename);
109-
}
110+
// If we're installing from a dump that's not already in
111+
// our local destination, copy it to our local destination.
112+
if (!empty($this->file)) {
113+
$this->file = $this->copy($this->file);
110114

111-
// Check if the file exits.
112-
if (!$this->is_absolute_path($this->filename)) {
113-
$filename = realpath(getcwd() . trim($this->filename, '.'));
114-
if (!$this->fileExists($filename)) {
115-
throw new SiteCommandException(sprintf('Dump file %s doesn\'t exist',
116-
$this->filename)
117-
);
118-
}
119-
else {
120-
$this->filename = $filename;
121-
}
115+
// If the file is gzipped we need to unzip it.
116+
$this->file = $this->unzip($this->file);
122117
}
123118

124119
$this->destination = $this->settingsPhpDirectory();
@@ -154,7 +149,7 @@ protected function execute(InputInterface $input, OutputInterface $output) {
154149
}
155150

156151
// If a dump file wasn't found or not specified, do a fresh site install
157-
if (!$this->fileExists($this->filename)) {
152+
if (empty($this->file) || !$this->fileExists($this->file)) {
158153
//@todo Use drupal site:install instead of Drush.
159154
$command = sprintf(
160155
'cd %s && ' .
@@ -169,62 +164,16 @@ protected function execute(InputInterface $input, OutputInterface $output) {
169164
$this->io->comment('Installing site');
170165
}
171166
else {
172-
$command = '';
173-
// Check the format of the dump.
174-
switch (mime_content_type($this->filename)) {
175-
case 'application/x-gzip':
176-
177-
// The basename without any path.
178-
$baseNameGz = basename($this->filename);
179-
180-
// The basename with sql extension.
181-
$baseNameSql = str_replace('.sql.gz', '.sql', $baseNameGz);
182-
183-
$this->io->write(sprintf('Checking if dump exists locally: '));
184-
if ($this->fileExists('/tmp/' . $baseNameGz)) {
185-
$this->io->writeln('Yes');
186-
}
187-
else {
188-
$this->io->writeln('No');
189-
}
190-
191-
$this->io->write(sprintf('Checking if local dump is up to date: '));
192-
if (filesize('/tmp/' . $baseNameGz) != filesize($this->filename)) {
193-
$this->io->writeln('No');
194-
195-
// Copy file to /tmp.
196-
$command .= sprintf(
197-
'cp -L %s /tmp; ',
198-
$this->filename
199-
);
200-
}
201-
else {
202-
$this->io->writeln('Yes');
203-
}
204-
205-
// Unzip sql file and keep zipped in the folder.
206-
$command .= sprintf(
207-
'cd /tmp; ' .
208-
'gunzip -c %s > %s; ',
209-
$baseNameGz,
210-
$baseNameSql
211-
);
212-
213-
// Use the file extracted on tmp folder.
214-
$this->filename = '/tmp/' . $baseNameSql;
215-
break;
216-
}
217-
218167
if (is_null($input->getOption('db-name'))) {
219168
$input->setOption('db-name', $this->siteName);
220169
}
221-
$command .= sprintf(
170+
$command = sprintf(
222171
'cd %s; ' .
223172
'drush sql-create %s -y; ' .
224173
'drush sql-cli < %s; ',
225174
$this->destination,
226175
$input->getOption('db-name'),
227-
$this->filename
176+
$this->file
228177
);
229178
$this->io->comment('Importing dump');
230179
}
@@ -249,24 +198,42 @@ protected function execute(InputInterface $input, OutputInterface $output) {
249198
}
250199

251200
/**
252-
* Downloads the dump from s3 bucket.
201+
* Downloads or copies the dump to a local destination.
253202
*
254-
* @param $filename
203+
* Can be copied from a remote or local desintaiton.
255204
*
256-
* @return string The absolute path for the dump.
205+
* @param $file
206+
* The file to be copied.
207+
*
208+
* @return string
209+
* The absolute path for the dump.
257210
*
258211
* @throws SiteCommandException
259212
*/
260-
protected function download($filename) {
261-
$tmp_folder = '/tmp/';
213+
protected function copy($file) {
214+
// Sanitise the input file path.
215+
$file = $this->cleanFileName($file);
216+
$filename = basename($file);
217+
218+
// Return canonicalized absolute pathname for local files.
219+
if (stream_is_local($file)) {
220+
$file = realpath($file);
221+
}
222+
223+
// Check we're not explicitly using a file in the local destination.
224+
if (substr($file, 0, strlen($this->tmpFolder)) === $this->tmpFolder) {
225+
return $file;
226+
}
262227

263-
// Save the dbdump to a local destination.
264-
if ('s3' === parse_url($filename, PHP_URL_SCHEME)) {
228+
// Save the db dump from S3 to the local destination.
229+
// We use S3cmd because the stream_wrapper isn't authenticated
230+
// and because it validates the checksum for us.
231+
if ('s3' === parse_url($file, PHP_URL_SCHEME)) {
265232
$command = sprintf(
266233
'cd %s && ' .
267-
's3cmd --force get %s',
268-
$tmp_folder,
269-
$filename
234+
's3cmd --force --check-md5 get %s',
235+
$this->tmpFolder,
236+
$file
270237
);
271238

272239
$shellProcess = $this->getShellProcess();
@@ -277,26 +244,87 @@ protected function download($filename) {
277244
throw new SiteCommandException($shellProcess->getOutput());
278245
}
279246
}
247+
// For all other methods including remote and local files
248+
// we copy chunk by chunk to the local destination.
280249
else {
250+
// Check the file isn't already downloaded.
251+
$this->io->write(sprintf('Checking if db dump needs updating: '));
252+
if ($this->fileExists($this->tmpFolder . $filename) && md5_file($this->tmpFolder . $filename) === md5_file($file)) {
253+
$this->io->writeln('No');
254+
return $this->tmpFolder . $filename;
255+
}
256+
$this->io->writeln('Yes');
257+
281258
// Open a stream in read-only mode
282-
if ($stream = fopen($filename, 'r')) {
259+
if ($stream = fopen($file, 'r')) {
283260
// Open the destination file to save the output to.
284-
$output_file = fopen ($tmp_folder . basename($filename), "a");
285-
if ($output_file)
286-
while(!feof($stream)) {
261+
$output_file = fopen($this->tmpFolder . $filename, "a");
262+
if ($output_file) {
263+
while (!feof($stream)) {
287264
fwrite($output_file, fread($stream, 1024), 1024);
288265
}
266+
}
289267
fclose($stream);
290268
if ($output_file) {
291269
fclose($output_file);
292270
}
293271
}
294272
else {
295-
throw new SiteCommandException("The DB dump could not be saved to the local destination.");
273+
throw new SiteCommandException("The DB dump does not exist or is not readable.");
296274
}
297275
}
298276

299-
return $tmp_folder . basename($filename);
277+
// Check that the db dump has been saved.
278+
if (!$this->fileExists($this->tmpFolder . $filename)) {
279+
throw new SiteCommandException("The DB dump could not be saved to the local destination.");
280+
}
281+
$this->io->success(sprintf('The DB dump was copied to %s.', $this->tmpFolder . $filename));
282+
283+
return $this->tmpFolder . $filename;
284+
}
285+
286+
/**
287+
* @param $file
288+
* The zipped file to be extracted.
289+
*
290+
* @return string
291+
* The unzipped file.
292+
*
293+
* @throws SiteCommandException
294+
*/
295+
public function unzip($file) {
296+
// The basename without any path.
297+
$baseNameGz = basename($file);
298+
// The basename with sql extension.
299+
$baseNameSql = rtrim($baseNameGz, '.gz');
300+
301+
// Unzip sql file and keep zipped in the folder.
302+
if (mime_content_type($this->file) === 'application/x-gzip') {
303+
$command = sprintf(
304+
'cd %s; ' .
305+
'gunzip -c %s > %s; ',
306+
$this->tmpFolder,
307+
$baseNameGz,
308+
$baseNameSql
309+
);
310+
}
311+
// Return the file without modification.
312+
else {
313+
return $file;
314+
}
315+
316+
// Run unzip command.
317+
$shellProcess = $this->getShellProcess();
318+
if ($shellProcess->exec($command, TRUE)) {
319+
$this->io->writeln($shellProcess->getOutput());
320+
$this->io->success(sprintf("The DB dump was unzipped to %s", $this->tmpFolder . $baseNameSql));
321+
}
322+
else {
323+
throw new SiteCommandException($shellProcess->getOutput());
324+
}
325+
326+
// Use the file extracted on tmp folder.
327+
return $this->tmpFolder . $baseNameSql;
300328
}
301329

302330
}

0 commit comments

Comments
 (0)