function drush_archive_dump

8.0.x archive.drush.inc drush_archive_dump($sites_subdirs = '@self')
6.x archive.drush.inc drush_archive_dump($sites_subdirs = '@self')
7.x archive.drush.inc drush_archive_dump($sites_subdirs = '@self')
4.x archive.drush.inc drush_archive_dump($sites_subdirs = '@self')
5.x archive.drush.inc drush_archive_dump($sites_subdirs = '@self')
master archive.drush.inc drush_archive_dump($sites_subdirs = '@self')

Command callback. Generate site archive file.

File

commands/core/archive.drush.inc, line 63
An early implementation of Site Archive dump/restore. See http://groups.drupal.org/site-archive-format.

Code

function drush_archive_dump($sites_subdirs = '@self') {
  $aliases = drush_sitealias_resolve_sitespecs(explode(',', $sites_subdirs));
  foreach ($aliases as $key => $alias) {
    if (($db_record = sitealias_get_databases_from_record($alias))) {
      $full[$key] = $alias += $db_record;
    }
    else {
      drush_log(dt('DB connections not found for !alias', array('!alias' => $alias)), 'error');
      return;
    }
  }

  // The user can specify a destination filepath or not. That filepath might
  // end with .gz, .tgz, or something else. At the end of this command we will
  // gzip a file, and we want it to end up with the user-specified name (if
  // any), but gzip renames files and refuses to compress files ending with
  // .gz and .tgz, making our lives difficult. Solution:
  //
  // 1. Create a unique temporary base name to which gzip WILL append .gz.
  // 2. If no destination is provided, set $dest_dir to a backup directory and
  // $final_destination to be the unique name in that dir.
  // 3. If a destination is provided, set $dest_dir to that directory and
  // $final_destination to the exact name given.
  // 4. Set $destination, the actual working file we will build up, to the
  // unqiue name in $dest_dir.
  // 5. After gzip'ing $destination, rename $destination.gz to
  // $final_destination.
  //
  // Sheesh.

  // Create the unique temporary name.
  $date = gmdate('Ymd_his');
  $first = current($full);
  $prefix = count($sites_subdirs) > 1 ? 'multiple_sites' : $first['default']['default']['database'];
  $temp_dest_name = "$prefix.$date.tar";

  $final_destination = drush_get_option('destination');
  if (!$final_destination) {
    // No destination provided.
    drush_include_engine('version_control', 'backup');
    $backup = new drush_pm_version_control_backup();
    // TODO: this standard drush pattern leads to a slightly obtuse directory structure.
    $dest_dir = $backup->prepare_backup_dir('archive-dump');
    if (empty($dest_dir)) {
      $dest_dir = drush_tempdir();
    }
    $final_destination = "$dest_dir/$temp_dest_name.gz";
  }
  else {
    // Use the supplied --destination. If it is relative, resolve it
    // relative to the directory in which drush was invoked.
    $command_cwd = getcwd();
    drush_op('chdir', drush_get_context('DRUSH_OLDCWD', getcwd()));
    // This doesn't perform realpath on the basename, but that's okay. This is
    // not path-based security. We just use it for checking for perms later.
    $dest_dir = realpath(dirname($final_destination));
    $final_destination = $dest_dir . '/' . basename($final_destination);
    drush_op('chdir', $command_cwd);
  }

  // $dest_dir is either the backup directory or specified directory. Set our
  // working file.
  $destination = "$dest_dir/$temp_dest_name";

  // Validate the FINAL destination. It should be a file that does not exist
  // (unless --overwrite) in a writable directory (and a writable file if
  // it exists). We check all this up front to avoid failing after a long
  // dump process.
  $overwrite = drush_get_option('overwrite');
  $dest_dir = dirname($final_destination);
  $dt_args = array(
    '!file' => $final_destination,
    '!dir' => $dest_dir,
  );
  if (is_dir($final_destination)) {
    drush_set_error('DRUSH_ARCHIVE_DEST_IS_DIR', dt('destination !file must be a file, not a directory.', $dt_args));
    return;
  }
  else if (file_exists($final_destination)) {
    if (!$overwrite) {
      drush_set_error('DRUSH_ARCHIVE_DEST_EXISTS', dt('destination !file exists; specify --overwrite to overwrite.', $dt_args));
      return;
    }
    else if (!is_writable($final_destination)) {
      drush_set_error('DRUSH_ARCHIVE_DEST_FILE_NOT_WRITEABLE', dt('destination !file is not writable.', $dt_args));
      return;
    }
  }
  else if (!is_writable(dirname($final_destination))) {
    drush_set_error('DRUSH_ARCHIVE_DEST_DIR_NOT_WRITEABLE', dt('destination directory !dir is not writable.', $dt_args));
    return;
  }

  $docroot_path = realpath(drush_get_context('DRUSH_DRUPAL_ROOT'));
  $docroot = basename($docroot_path);
  $workdir = dirname($docroot_path);
  $dereference = (drush_get_option('preserve-symlinks', FALSE)) ? '' : '--dereference ';
  // Archive Drupal core, excluding sites dir.
  drush_shell_cd_and_exec($workdir, "tar --exclude '{$docroot}/sites' {$dereference}-cf %s %s", $destination, $docroot);
  // Add sites/all to the same archive.
  drush_shell_cd_and_exec($workdir, "tar {$dereference}-rf %s %s", $destination, "{$docroot}/sites/all");

  // Dump the default database for each site and add to the archive.
  foreach ($full as $key => $alias) {
    if ($db = $alias['databases']['default']['default']) {
      $tmp = drush_tempdir();
      // Use a subdirectory name matching the docroot name.
      drush_mkdir("{$tmp}/{$docroot}");
      // Ensure uniqueness by prefixing key if needed.
      $dbname = $db['database'];
      $result_file = count($full) == 1 ? "$tmp/$dbname.sql" : str_replace('@', '', "$tmp/$key-$dbname.sql");
      $all_dbs[$key] = array(
        'file' => $result_file,
        'driver' => $db['driver'],
      );
      drush_set_option('result-file', $result_file);
      $table_selection = drush_sql_get_table_selection();
      list($dump_exec, $dump_file) = drush_sql_build_dump_command($table_selection, $db);
      drush_shell_exec($dump_exec);
      drush_shell_cd_and_exec($tmp, 'tar --dereference -rf %s %s', $destination, basename($result_file));
    }
  }

  // Build a manifest file AND add sites/$subdir to archive as we go.
  $platform = array(
    'datestamp' => time(),
    'formatversion' => '1.0',
    'generator' => drush_get_option('generator', 'Drush archive-dump'),
    'generatorversion' => drush_get_option('generatorversion', DRUSH_VERSION),
    'description' => drush_get_option('description', ''),
    'tags' => drush_get_option('tags', ''),
  );
  $contents = drush_export_ini(array('Global' => $platform));

  $i = 0;
  foreach ($full as $key => $alias) {
    $status = drush_invoke_sitealias_args($alias, 'core-status', array(), array());

    // Add the site specific directory to archive.
    if (!empty($status['object']['%paths']['%site'])) {
      drush_shell_cd_and_exec($workdir, "tar --dereference -rf %s %s", $destination, "{$docroot}/sites/" . basename($status['object']['%paths']['%site']));
    }

    $site = array(
      'docroot' => DRUPAL_ROOT,
      'sitedir' => @$status['object']['%paths']['%site'],
      'files-public' => @$status['object']['%paths']['%files'],
      'files-private' => @$status['object']['%paths']['%private'],
    );
    // Add info for each DB connection (usually only 1);
    foreach ($all_dbs as $dbkey => $db) {
      $site["database-default-file"] = basename($db['file']);
      $site["database-default-driver"] = $db['driver'];
    }
    // The section title is the sites subdirectory name.
    $info[basename($site['sitedir'])] = $site;
    $contents .= "\n" . drush_export_ini($info);
    unset($info);
    $i++;
  }
  file_put_contents("{$tmp}/MANIFEST.ini", $contents);

  // Add manifest to archive.
  drush_shell_cd_and_exec($tmp, 'tar --dereference -rf %s %s', $destination, "MANIFEST.ini");

  // Compress the archive
  drush_shell_exec("gzip --no-name -f %s", $destination);

  // gzip appends .gz unless the name already ends in .gz, .tgz, or .taz.
  if ("{$destination}.gz" != $final_destination) {
    drush_move_dir("{$destination}.gz", $final_destination, $overwrite);
  }

  drush_log(dt('Archive saved to !dest', array('!dest' => $final_destination)), 'ok');
  drush_print_pipe($final_destination);
  return $final_destination;
}