diff --git a/commands/core/archive.drush.inc b/commands/core/archive.drush.inc index 632ab25..9b84571 100644 --- a/commands/core/archive.drush.inc +++ b/commands/core/archive.drush.inc @@ -21,7 +21,7 @@ function archive_drush_command() { 'generatorversion' => 'The generator version number to store in the MANIFEST file. The default is ' . DRUSH_VERSION . '.', 'pipe' => 'Only print the destination of the archive. Useful for scripts that don\'t pass --destination.', 'preserve-symlinks' => 'Preserve symbolic links.', - 'no-core' => 'Exclude Drupal core, but keep the sites/default or sites/example.com directory.', + 'no-core' => 'Exclude Drupal core, so the backup only contains the site specific stuff.', 'tar-options' => 'Options passed thru to the tar command.', ), 'examples' => array( @@ -66,15 +66,11 @@ function archive_drush_command() { * Command callback. Generate site archive file. */ function drush_archive_dump($sites_subdirs = '@self') { + $include_platform = !drush_get_option('no-core', FALSE); $tar = drush_get_tar_executable(); + $sites = array(); $aliases = drush_sitealias_resolve_sitespecs(explode(',', $sites_subdirs)); - - $include_platform = TRUE; - if (drush_get_option('no-core', FALSE)) { - $include_platform = FALSE; - } - foreach ($aliases as $key => $alias) { $sites[$key] = $alias; if (($db_record = sitealias_get_databases_from_record($alias))) { @@ -230,7 +226,7 @@ function drush_archive_dump($sites_subdirs = '@self') { 'generatorversion' => drush_get_option('generatorversion', DRUSH_VERSION), 'description' => drush_get_option('description', ''), 'tags' => drush_get_option('tags', ''), - 'archivedformat' => ($include_platform ? 'platform' : 'site'), + 'archiveformat' => ($include_platform ? 'platform' : 'site'), ); $contents = drush_export_ini(array('Global' => $platform)); @@ -312,7 +308,21 @@ function drush_archive_restore($file, $site_id = NULL) { return drush_set_error('DRUSH_ARCHIVE_UNABLE_TO_EXTRACT', dt('Unable to extract site archive tarball to !tmp.', array('!tmp' => $tmp))); } - $ini = drush_archive_read_manifest($tmp); + $manifest = $tmp . '/MANIFEST.ini'; + if (file_exists($manifest)) { + if (!$ini = parse_ini_file($manifest, TRUE)) { + return drush_set_error('DRUSH_ARCHIVE_UNABLE_TO_PARSE_MANIFEST', dt('Unable to parse MANIFEST.ini in the archive.')); + } + } + else { + $ini = drush_archive_guess_manifest($tmp); + } + + // Backward compatibility: 'archiveformat' did not exist + // in older versions of archive-dump. + if (!isset( $ini['Global']['archiveformat'])) { + $ini['Global']['archiveformat'] = 'platform'; + } // Grab the first site in the Manifest and move docroot to destination. $ini_tmp = $ini; @@ -321,28 +331,28 @@ function drush_archive_restore($file, $site_id = NULL) { $docroot = basename($first['docroot']); $destination = drush_get_option('destination', realpath('.') . "/$docroot"); - if ($ini['Global']['archive_format'] == 'platform') { + if ($ini['Global']['archiveformat'] == 'platform') { // Move the whole platform inplace at once. if (!drush_move_dir("$tmp/$docroot", $destination, drush_get_option('overwrite'))) { - return drush_set_error('DRUSH_ARCHIVE_UNABLE_RESTORE_FILES', dt('Unable to restore platform to !dest', array('!dest' => $destination))); + return drush_set_error('DRUSH_ARCHIVE_UNABLE_TO_RESTORE_FILES', dt('Unable to restore platform to !dest', array('!dest' => $destination))); } - } else { - // When no platform is included we do this on a per-site basis - + } + else { + // When no platform is included we do this on a per-site basis. } // Loop over sites and restore databases and append to settings.php. foreach ($ini as $section => $site) { if ($section != 'Global' && (is_null($site_id) || $section == $site_id) && !empty($site['database-default-file'])) { $site_destination = $destination . '/' . $site['sitedir']; - // Restore site, incase not already done above - if ($ini['Global']['archive_format'] == 'site') { + // Restore site, in case not already done above. + if ($ini['Global']['archiveformat'] == 'site') { if (!drush_move_dir("$tmp/$docroot/" . $site['sitedir'], $site_destination, drush_get_option('overwrite'))) { - return drush_set_error('DRUSH_ARCHIVE_UNABLE _RESTORE_FILES', dt('Unable to restore site to !dest', array('!dest' => $site_destination))); + return drush_set_error('DRUSH_ARCHIVE_UNABLE_TO_RESTORE_FILES', dt('Unable to restore site to !dest', array('!dest' => $site_destination))); } } - // Restore database + // Restore database. $sql_file = $tmp . '/' . $site['database-default-file']; if ($db_url = drush_get_option('db-url')) { if (empty($site_id) && count($ini) >= 3) { @@ -385,6 +395,7 @@ function drush_archive_restore($file, $site_id = NULL) { } } drush_log(dt('Archive restored to !dest', array('!dest' => $destination)), 'ok'); + return $destination; } @@ -410,47 +421,33 @@ function archive_archive_restore_complete() { } /** - * Read and parse the MANIFEST from an extracted archive + * Try to find docroot and DB dump file in an extracted archive. * - * @param string $path The location of theextracted archive - * @return array The manifest data + * @param string $path The location of the extracted archive. + * @return array The manifest data. */ -function drush_archive_read_manifest($path) { - $manifest = $path . '/MANIFEST.ini'; - if (file_exists($manifest)) { - if (!$ini = parse_ini_file($manifest, TRUE)) { - return drush_set_error('DRUSH_ARCHIVE_UNABLE_TO_PARSE_MANIFEST', dt('Unable to parse MANIFEST.ini in the archive.')); - } +function drush_archive_guess_manifest($path) { + $db_file = drush_scan_directory($path, '/\.sql$/', array('.', '..', 'CVS'), 0, 0); + + if (file_exists($path . '/index.php')) { + $docroot = './'; } else { - // No manifest. Try to find docroot and DB dump file. - $db_file = drush_scan_directory($path, '/\.sql$/', array('.', '..', 'CVS'), 0, 0); - - if (file_exists($path . '/index.php')) { - $docroot = './'; - } - else { - $directories = glob($path . '/*' , GLOB_ONLYDIR); - $docroot = reset($directories); - } - - $ini = array( - 'Global' => array( - // Very crude detection of a platform... - 'archive_format' => (drush_drupal_version($docroot) ? 'platform' : 'site'), - ), - 'default' => array( - 'docroot' => $docroot, - 'sitedir' => 'sites/default', - 'database-default-file' => key($db_file), - ), - ); + $directories = glob($path . '/*' , GLOB_ONLYDIR); + $docroot = reset($directories); } - // Format compatibility, for 1.0 this option initially did not exist. - if (!isset( $ini['Global']['archive_format'])) { - $ini['Global']['archive_format'] = 'platform'; - } + $ini = array( + 'Global' => array( + // Very crude detection of a platform... + 'archiveformat' => (drush_drupal_version($docroot) ? 'platform' : 'site'), + ), + 'default' => array( + 'docroot' => $docroot, + 'sitedir' => 'sites/default', + 'database-default-file' => key($db_file), + ), + ); return $ini; } diff --git a/tests/archiveDumpTest.php b/tests/archiveDumpTest.php index ec87edd..a078a06 100644 --- a/tests/archiveDumpTest.php +++ b/tests/archiveDumpTest.php @@ -6,142 +6,127 @@ * @group commands */ class archiveDumpCase extends Drush_CommandTestCase { + /** + * archive-dump behaves slightly different when archiving a site installed + * at sites/default so we make the test to use sites/default as the + * installation directory instead of default sites/dev. + */ + const uri = 'default'; - /* - * Test dump and extraction. - * - * archive-dump behaves slightly different when archiving a site installed at sites/default - * so we make the test to use sites/default as the installation directory. + /** + * Install a site and dump it to an archive. */ - public function testArchiveDump() { - $uri = 'default'; - $this->fetchInstallDrupal($uri, TRUE, UNISH_DRUPAL_MAJOR_VERSION, 'testing'); + private function archiveDump($no_core) { + $this->fetchInstallDrupal(self::uri, TRUE, UNISH_DRUPAL_MAJOR_VERSION, 'testing'); $root = $this->webroot(); - $docroot = basename($root); - - $dump_dest = "dump.tar.gz"; + $dump_dest = UNISH_SANDBOX . DIRECTORY_SEPARATOR . 'dump.tar.gz'; $options = array( 'root' => $root, - 'uri' => $uri, + 'uri' => self::uri, 'yes' => NULL, 'destination' => $dump_dest, + 'overwrite' => NULL, ); - $this->drush('archive-dump', array($uri), $options); - $exec = sprintf('file %s%s%s', UNISH_SANDBOX, DIRECTORY_SEPARATOR, $dump_dest); - $this->execute($exec); - $output = $this->getOutput(); - $sep = self::is_windows() ? ';' : ':'; - $expected = UNISH_SANDBOX . DIRECTORY_SEPARATOR . "dump.tar.gz$sep gzip compressed data, from"; + if ($no_core) { + $options['no-core'] = NULL; + } + $this->drush('archive-dump', array(self::uri), $options); - $this->assertStringStartsWith($expected, $output); + return $dump_dest; + } - // Untar it, make sure it looks right. + /** + * Untar an archive and return the path to the untarred folder. + */ + private function unTar($dump_dest) { $untar_dest = UNISH_SANDBOX . DIRECTORY_SEPARATOR . 'untar'; + unish_file_delete_recursive($untar_dest); $tar = self::get_tar_executable(); - $exec = sprintf("mkdir %s && cd %s && $tar -xzf %s%s%s", $untar_dest, $untar_dest, UNISH_SANDBOX, DIRECTORY_SEPARATOR, $dump_dest); + $exec = sprintf("mkdir %s && cd %s && $tar -xzf %s", $untar_dest, $untar_dest, $dump_dest); $this->execute($exec); + return $untar_dest; + } + + /** + * Test if tarball generated by archive-dump looks right. + */ + public function testArchiveDump() { + $dump_dest = $this->archiveDump(FALSE); + $docroot = basename($this->webroot()); + + // Check the dump file is a gzip file. + $exec = sprintf('file %s', $dump_dest); + $this->execute($exec); + $output = $this->getOutput(); + $sep = self::is_windows() ? ';' : ':'; + $expected = $dump_dest . "$sep gzip compressed data, from"; + $this->assertStringStartsWith($expected, $output); + + // Untar the archive and make sure it looks right. + $untar_dest = $this->unTar($dump_dest); + if (strpos(UNISH_DB_URL, 'mysql') !== FALSE) { - $this->execute(sprintf('head %s/unish_%s.sql | grep "MySQL dump"', $untar_dest, $uri)); + $this->execute(sprintf('head %s/unish_%s.sql | grep "MySQL dump"', $untar_dest, self::uri)); } $this->assertFileExists($untar_dest . '/MANIFEST.ini'); $this->assertFileExists($untar_dest . '/' . $docroot); - // Restore archive and verify that the file structure is identical. + return $dump_dest; + } + + /** + * Test archive-restore. + * + * Restore the archive generated in testArchiveDump() and verify that the + * directory contents are identical. + * + * @depends testArchiveDump + */ + public function testArchiveRestore($dump_dest) { require_once dirname(__FILE__) . '/../includes/filesystem.inc'; $restore_dest = UNISH_SANDBOX . DIRECTORY_SEPARATOR . 'restore'; $options = array( 'yes' => NULL, 'destination' => $restore_dest, ); - $this->drush('archive-restore', array(UNISH_SANDBOX . DIRECTORY_SEPARATOR . $dump_dest), $options); - $original_codebase = drush_dir_md5($root); + $this->drush('archive-restore', array($dump_dest), $options); + $original_codebase = drush_dir_md5($this->webroot()); $restored_codebase = drush_dir_md5($restore_dest); $this->assertEquals($original_codebase, $restored_codebase); - - // Cleanup - unish_file_delete_recursive($untar_dest); - unish_file_delete_recursive(UNISH_SANDBOX . '/' . $dump_dest); } - /* - * Test dump and extraction with --no-core. + /** + * Test if tarball generated by archive-dump with --no-core looks right. */ public function testArchiveDumpNoCore() { - $sites = $this->setUpDrupal(1, TRUE); - $site = reset($sites); - $root = $this->webroot(); - $uri = key($sites); - $docroot = basename($root); - - $dump_dest = "dump.tar.gz"; - $options = array( - 'root' => $root, - 'uri' => $uri, - 'yes' => NULL, - 'no-core' => TRUE, - 'destination' => $dump_dest, - ); - $this->drush('archive-dump', array($uri), $options); - $exec = sprintf('file %s/%s', UNISH_SANDBOX, $dump_dest); - $this->execute($exec); - $output = $this->getOutput(); - $expected = UNISH_SANDBOX . "/dump.tar.gz: gzip compressed data, from Unix"; - $this->assertEquals($expected, $output); - - // Untar it, make sure it looks right. - $untar_dest = UNISH_SANDBOX . '/untar'; - $exec = sprintf('mkdir %s && cd %s && tar xzf %s/%s', $untar_dest, $untar_dest, UNISH_SANDBOX, $dump_dest); - $this->execute($exec); - - if (strpos(UNISH_DB_URL, 'mysql') !== FALSE) { - $this->execute(sprintf('head %s/unish_%s.sql | grep "MySQL dump"', $untar_dest, $uri)); - } - $this->assertFileExists($untar_dest . '/MANIFEST.ini', 'MANIFEST.ini should exist'); - $this->execute('test -d ' . $untar_dest . '/' . $docroot); + $dump_dest = $this->archiveDump(TRUE); + $untar_dest = $this->unTar($dump_dest); + $docroot = basename($this->webroot()); + $this->assertFileExists($untar_dest . '/MANIFEST.ini'); + $this->assertFileExists($untar_dest . '/' . $docroot); $this->assertFileNotExists($untar_dest . '/' . $docroot . '/modules', 'No modules directory should exist with --no-core'); - // Cleanup - unish_file_delete_recursive($untar_dest); - unish_file_delete_recursive(UNISH_SANDBOX . '/' . $dump_dest); + return $dump_dest; } - - /* - * Test dump and extraction with --no-core. + /** + * Test archive-restore for a site archive (--no-core). + * + * @depends testArchiveDumpNoCore */ - public function testArchiveRestoreNoCore() { - $sites = $this->setUpDrupal(1, TRUE); - $site = reset($sites); + public function testArchiveRestoreNoCore($dump_dest) { $root = $this->webroot(); - $uri = key($sites); - $docroot = basename($root); + $original_codebase = drush_dir_md5($root); + unish_file_delete_recursive($root . '/sites/' . self::uri); - $dump_dest = "dump.tar.gz"; - $dump_dest_path = UNISH_SANDBOX . '/' . $dump_dest ; $options = array( - 'root' => $root, - 'uri' => $uri, 'yes' => NULL, - 'no-core' => TRUE, // <<-- The option being tested here - 'destination' => $dump_dest, + 'destination' => $root, ); - $this->drush('archive-dump', array($uri), $options); - - unish_file_delete_recursive($root . '/sites/dev'); - $this->assertFileNotExists($root . '/sites/dev/settings.php', 'settings.php should have been removed before the restore'); - $options = array( - 'overwrite' => TRUE, - ); + $this->drush('archive-restore', array($dump_dest), $options); - // Do the restore - $this->drush('archive-restore',array($dump_dest_path), $options); - - // Verify - $this->assertFileExists($root . '/index.php'); - $this->assertFileExists($root . '/sites/dev/settings.php', 'settings.php should have been recreated by the restore'); - - // Cleanup - unish_file_delete_recursive(UNISH_SANDBOX . '/' . $dump_dest); + $restored_codebase = drush_dir_md5($root); + $this->assertEquals($original_codebase, $restored_codebase); } }