Exemple #1
0
 /**
  * Get help on a certain command.
  *
  * [<commands>...]
  * : The command you want information on
  *
  * [--recursive]
  * : Display full information on all subcommands and their subcommands
  *
  * ## EXAMPLES
  *
  *     # get help for `sites` command
  *     terminus help sites
  *
  *     # get help for `sites` command and all its subcommands
  *     terminus help sites --recursive
  *
  *     # get help for `sites list` subcommand
  *     terminus help sites list
  */
 public function __invoke($args, $assoc_args)
 {
     $this->recursive = Input::optional(array('key' => 'recursive', 'choices' => $assoc_args, 'default' => false));
     $command = $this->findSubcommand($args);
     if ($command) {
         $status = $this->showHelp($command);
         exit($status);
     }
     $this->failure('"{cmd}" is not a registered command.', array('cmd' => $args[0]));
 }
Exemple #2
0
 /**
  * Lists available backups
  *
  * @params [array] $assoc_args Parameters and flags from the command line
  * @return [array] $data Elements as follows:
  *         [string] file The backup's file name
  *         [string] size The backup file's size
  *         [string] date The datetime of the backup's creation
  */
 private function listBackups($assoc_args)
 {
     $site = $this->sites->get(Input::sitename($assoc_args));
     $env = $site->environments->get(Input::env(array('args' => $assoc_args, 'site' => $site)));
     $element = null;
     if (isset($assoc_args['element']) && $assoc_args['element'] != 'all') {
         $element = Input::backupElement(array('args' => $assoc_args));
     }
     $backups = $env->backups->getFinishedBackups($element);
     $latest = (bool) Input::optional('latest', $assoc_args, false);
     if (empty($backups)) {
         $this->log()->warning('No backups found.');
     } else {
         if ($latest) {
             array_splice($backups, 1);
         }
         $data = array();
         foreach ($backups as $id => $backup) {
             $data[] = array('file' => $backup->get('filename'), 'size' => $backup->getSizeInMb(), 'date' => $backup->getDate(), 'initiator' => $backup->getInitiator());
         }
         return $data;
     }
 }
Exemple #3
0
 /**
  * Update alls dev sites with an available upstream update.
  *
  * ## OPTIONS
  *
  * [--report]
  * : If set output will contain list of sites and whether they are up-to-date
  *
  * [--upstream=<upstream>]
  * : Specify a specific upstream to check for updating.
  *
  * [--no-updatedb]
  * : Use flag to skip running update.php after the update has applied
  *
  * [--xoption=<theirs|ours>]
  * : Corresponds to git's -X option, set to 'theirs' by default -- https://www.kernel.org/pub/software/scm/git/docs/git-merge.html
  *
  * @subcommand mass-update
  */
 public function mass_update($args, $assoc_args)
 {
     $sites = SiteFactory::instance();
     $env = 'dev';
     $upstream = Input::optional('upstream', $assoc_args, false);
     $data = array();
     $report = Input::optional('report', $assoc_args, false);
     $confirm = Input::optional('confirm', $assoc_args, false);
     // Start status messages.
     if ($upstream) {
         Terminus::line('Looking for sites using ' . $upstream . '.');
     }
     foreach ($sites as $site) {
         $updates = $site->getUpstreamUpdates();
         if (!isset($updates->behind)) {
             // No updates, go back to start.
             continue;
         }
         // Check for upstream argument and site upstream URL match.
         $siteUpstream = $site->info('upstream');
         if ($upstream and isset($siteUpstream->url)) {
             if ($siteUpstream->url != $upstream) {
                 // Uptream doesn't match, go back to start.
                 continue;
             }
         }
         if ($updates->behind > 0) {
             $data[$site->getName()] = array('site' => $site->getName(), 'status' => "Needs update");
             $noupdatedb = Input::optional($assoc_args, 'updatedb', false);
             $update = $noupdatedb ? false : true;
             $xoption = Input::optional($assoc_args, 'xoption', 'theirs');
             if (!$report) {
                 $confirmed = Input::yesno("Apply upstream updatefs to %s ( run update.php:%s, xoption:%s ) ", array($site->getName(), var_export($update, 1), var_export($xoption, 1)));
                 if (!$confirmed) {
                     continue;
                 }
                 // Suer says No, go back to start.
                 // Backup the DB so the client can restore if something goes wrong.
                 Terminus::line('Backing up ' . $site->getName() . '.');
                 $backup = $site->environment('dev')->createBackup(array('element' => 'all'));
                 // Only continue if the backup was successful.
                 if ($backup) {
                     Terminus::success("Backup of " . $site->getName() . " created.");
                     Terminus::line('Updating ' . $site->getName() . '.');
                     // Apply the update, failure here would trigger a guzzle exception so no need to validate success.
                     $response = $site->applyUpstreamUpdates($env, $update, $xoption);
                     $data[$site->getName()]['status'] = 'Updated';
                     Terminus::success($site->getName() . ' is updated.');
                 } else {
                     $data[$site->getName()]['status'] = 'Backup failed';
                     Terminus::error('There was a problem backing up ' . $site->getName() . '. Update aborted.');
                 }
             }
         } else {
             if (isset($assoc_args['report'])) {
                 $data[$site->getName()] = array('site' => $site->getName(), 'status' => "Up to date");
             }
         }
     }
     if (!empty($data)) {
         sort($data);
         $this->handleDisplay($data);
     } else {
         Terminus::line('No sites in need up updating.');
     }
 }
Exemple #4
0
 /**
  * Change the site payment instrument
  *
  * ## OPTIONS
  *
  * [--site=<site>]
  * : Site to use
  *
  * [--change-to-org=<org>]
  * : Change the instrument to an Org by setting the id. ( must be admin )
  *
  * ## EXAMPLES
  *
  *  terminus site instrument --site=sitename
  */
 public function instrument($args, $assoc_args)
 {
     $site = SiteFactory::instance(Input::site($assoc_args));
     $org = Input::optional('change-to-org', $assoc_args);
     $data = $site->instrument($org);
     // @TODO we need a "workflow" class to handle these exceptions and whatnot
     if ($org) {
         if ('failed' == $data->result || 'aborted' == $data->result) {
             if (isset($data->final_task) and !empty($data->final_task->messages)) {
                 foreach ((array) $data->final_task->messages as $date => $message) {
                     \Terminus::error('%s', $message->message);
                 }
             }
         }
         if ($data->result != 'succeeded') {
             $this->waitOnWorkflow('workflow', $site->getId(), $data->id);
         }
         $data = $site->instrument();
     }
     \Terminus::line("Successfully updated payment instrument.");
     $this->handleDisplay($data);
 }
Exemple #5
0
 /**
  * Get, load, create, or list backup information
  *
  * ## OPTIONS
  *
  * <get|load|create|list>
  * : Function to run - get, load, create, or list
  *
  * [--site=<site>]
  * : Site to load
  *
  * [--env=<env>]
  * : Environment to load
  *
  * [--element=<code|files|db|all>]
  * : Element to download or create. `all` is only used for 'create'
  *
  * [--to=<directory|file>]
  * : Absolute path of a directory or filename to save the downloaded backup to
  *
  * [--file=<filename>]
  * : Select one of the files from the list subcommand. Only used for 'get'
  *
  * [--latest]
  * : If set the latest backup will be selected automatically
  *
  * [--keep-for]
  * : Number of days to keep this backup
  *
  * @subcommand backups
  *
  */
 public function backups($args, $assoc_args)
 {
     $action = array_shift($args);
     $site = $this->sites->get(Input::sitename($assoc_args));
     $env = $site->environments->get(Input::env($assoc_args, 'env'));
     //Backward compatability supports "database" as a valid element value.
     if (isset($assoc_args['element']) && $assoc_args['element'] == 'database') {
         $assoc_args['element'] = 'db';
     }
     switch ($action) {
         case 'get':
             $file = Input::optional('file', $assoc_args, false);
             if ($file) {
                 $backup = $env->getBackupByFile($file);
                 $element = $backup->element;
             } else {
                 $element = Input::backupElement(array('args' => $assoc_args));
                 $latest = (bool) Input::optional('latest', $assoc_args, false);
                 $backups = $env->getFinishedBackups($element);
                 if ($latest) {
                     $backup = array_pop($backups);
                 } else {
                     $context = array('site' => $site->get('name'), 'env' => $env->get('id'));
                     $backup = Input::backup(array('backups' => $backups, 'context' => $context));
                 }
             }
             $url = $env->getBackupUrl($backup->folder, $element);
             if (isset($assoc_args['to'])) {
                 $target = str_replace('~', $_SERVER['HOME'], $assoc_args['to']);
                 if (is_dir($target)) {
                     $filename = Utils\getFilenameFromUrl($url->url);
                     $target = sprintf('%s/%s', $target, $filename);
                 }
                 $this->log()->info('Downloading ... please wait ...');
                 if ($this->download($url->url, $target)) {
                     $this->log()->info('Downloaded {target}', compact('target'));
                     return $target;
                 } else {
                     $this->failure('Could not download file');
                 }
             }
             $this->output()->outputValue($url->url, 'Backup URL');
             return $url->url;
             break;
         case 'load':
             $assoc_args['to'] = '/tmp';
             $assoc_args['element'] = 'database';
             if (isset($assoc_args['database'])) {
                 $database = $assoc_args['database'];
             } else {
                 $database = escapeshellarg(Terminus::prompt('Name of database to import to'));
             }
             if (isset($assoc_args['username'])) {
                 $username = $assoc_args['username'];
             } else {
                 $username = escapeshellarg(Terminus::prompt('Username'));
             }
             if (isset($assoc_args['password'])) {
                 $password = $assoc_args['password'];
             } else {
                 $password = escapeshellarg(Terminus::prompt('Password'));
             }
             exec('mysql -e "show databases"', $stdout, $exit);
             if ($exit != 0) {
                 $this->failure('MySQL does not appear to be installed on your server.');
             }
             $assoc_args['env'] = $env->get('id');
             $target = $this->backup(array('get'), $assoc_args);
             $target = '/tmp/' . Utils\getFilenameFromUrl($target);
             if (!file_exists($target)) {
                 $this->failure('Cannot read database file {target}', array('target' => $target));
             }
             $this->log()->info('Unziping database');
             exec("gunzip {$target}", $stdout, $exit);
             // trim the gz of the target
             $target = Utils\sqlFromZip($target);
             $target = escapeshellarg($target);
             exec("mysql {$database} -u {$username} -p'{$password}' < {$target}", $stdout, $exit);
             if ($exit != 0) {
                 $this->failure('Could not import database');
             }
             $this->log()->info('{target} successfully imported to {db}', array('target' => $target, 'db' => $database));
             return true;
             break;
         case 'create':
             if (!array_key_exists('element', $assoc_args)) {
                 $options = array('code', 'db', 'files', 'all');
                 $assoc_args['element'] = $options[Input::menu($options, 'all', 'Select element')];
             }
             $workflow = $env->createBackup($assoc_args);
             $workflow->wait();
             $this->workflowOutput($workflow);
             break;
         case 'list':
         default:
             $backups = $env->getBackups();
             $element_name = false;
             if (isset($assoc_args['element']) && $assoc_args['element'] != 'all') {
                 $element_name = $assoc_args['element'];
             }
             if ($element_name == 'db') {
                 $element_name = 'database';
             }
             $data = array();
             foreach ($backups as $id => $backup) {
                 if (!isset($backup->filename) || $element_name && !preg_match(sprintf('/_%s/', $element_name), $id)) {
                     continue;
                 }
                 $date = 'Pending';
                 if (isset($backup->finish_time)) {
                     $date = date('Y-m-d H:i:s', $backup->finish_time);
                 }
                 $size = 0;
                 if (isset($backup->size)) {
                     $size = $backup->size / 1048576;
                 }
                 if ($size > 0.1) {
                     $size = sprintf('%.1fMB', $size);
                 } elseif ($size > 0) {
                     $size = '0.1MB';
                 } else {
                     //0-byte backups should not be recommended for restoration
                     $size = 'Incomplete';
                 }
                 $data[] = array('file' => $backup->filename, 'size' => $size, 'date' => $date);
             }
             if (empty($data)) {
                 $this->log()->warning('No backups found.');
             }
             $this->output()->outputRecordList($data, array('file' => 'File', 'size' => 'Size', 'date' => 'Date'));
             return $data;
             break;
     }
 }
Exemple #6
0
 /**
  * Update alls dev sites with an available upstream update.
  *
  * ## OPTIONS
  *
  * [--report]
  * : If set output will contain list of sites and whether they are up-to-date
  *
  * [--upstream=<upstream>]
  * : Specify a specific upstream to check for updating.
  *
  * [--no-updatedb]
  * : Use flag to skip running update.php after the update has applied
  *
  * [--xoption=<theirs|ours>]
  * : Corresponds to git's -X option, set to 'theirs' by default -- https://www.kernel.org/pub/software/scm/git/docs/git-merge.html
  *
  * [--tag=<tag>]
  * : Tag to filter by
  *
  * [--org=<id>]
  * : Only necessary if using --tag. Organization which has tagged the site thusly
  *
  * [--cached]
  * : Set to prevent rebuilding of sites cache
  *
  * @subcommand mass-update
  */
 public function mass_update($args, $assoc_args)
 {
     // Ensure the sitesCache is up to date
     if (!isset($assoc_args['cached'])) {
         $this->sites->rebuildCache();
     }
     $upstream = Input::optional('upstream', $assoc_args, false);
     $data = array();
     $report = Input::optional('report', $assoc_args, false);
     $confirm = Input::optional('confirm', $assoc_args, false);
     $tag = Input::optional('tag', $assoc_args, false);
     $org = '';
     if ($tag) {
         $org = Input::orgid($assoc_args, 'org');
     }
     $sites = $this->sites->filterAllByTag($tag, $org);
     // Start status messages.
     if ($upstream) {
         $this->log()->info('Looking for sites using ' . $upstream . '.');
     }
     foreach ($sites as $site) {
         $site->fetch();
         $updates = $site->getUpstreamUpdates();
         if (!isset($updates->behind)) {
             // No updates, go back to start.
             continue;
         }
         // Check for upstream argument and site upstream URL match.
         $siteUpstream = $site->info('upstream');
         if ($upstream and isset($siteUpstream->url)) {
             if ($siteUpstream->url != $upstream) {
                 // Uptream doesn't match, go back to start.
                 continue;
             }
         }
         if ($updates->behind > 0) {
             $data[$site->get('name')] = array('site' => $site->get('name'), 'status' => "Needs update");
             $env = $site->environments->get('dev');
             if ($env->getConnectionMode() == 'sftp') {
                 $this->log()->warning('{site} has available updates, but is in SFTP mode. Switch to Git mode to apply updates.', array('site' => $site->get('name')));
                 $data[$site->get('name')] = array('site' => $site->get('name'), 'status' => "Needs update - switch to Git mode");
                 continue;
             }
             $updatedb = !Input::optional($assoc_args, 'updatedb', false);
             $xoption = Input::optional($assoc_args, 'xoption', 'theirs');
             if (!$report) {
                 $confirmed = Input::yesno("Apply upstream updates to %s ( run update.php:%s, xoption:%s ) ", array($site->get('name'), var_export($updatedb, 1), var_export($xoption, 1)));
                 if (!$confirmed) {
                     continue;
                 }
                 // User says No, go back to start.
                 // Backup the DB so the client can restore if something goes wrong.
                 $this->log()->info('Backing up ' . $site->get('name') . '.');
                 $backup = $env->createBackup(array('element' => 'all'));
                 // Only continue if the backup was successful.
                 if ($backup) {
                     $this->log()->info("Backup of " . $site->get('name') . " created.");
                     $this->log()->info('Updating ' . $site->get('name') . '.');
                     // Apply the update, failure here would trigger a guzzle exception so no need to validate success.
                     $response = $site->applyUpstreamUpdates($env->get('id'), $updatedb, $xoption);
                     $data[$site->get('name')]['status'] = 'Updated';
                     $this->log()->info($site->get('name') . ' is updated.');
                 } else {
                     $data[$site->get('name')]['status'] = 'Backup failed';
                     $this->log()->error('There was a problem backing up ' . $site->get('name') . '. Update aborted.');
                 }
             }
         } else {
             if (isset($assoc_args['report'])) {
                 $data[$site->get('name')] = array('site' => $site->get('name'), 'status' => "Up to date");
             }
         }
     }
     if (!empty($data)) {
         sort($data);
         $this->output()->outputRecordList($data);
     } else {
         $this->log()->info('No sites in need of updating.');
     }
 }
Exemple #7
0
 /**
  * Get, load, create, or list backup information
  *
  * ## OPTIONS
  *
  * <get|load|create|list>
  * : Function to run - get, load, create, or list
  *
  * [--site=<site>]
  * : Site to load
  *
  * [--env=<env>]
  * : Environment to load
  *
  * [--element=<code|files|db|all>]
  * : Element to download or create. `all` is only used for 'create'
  *
  * [--to=<directory|file>]
  * : Absolute path of a directory or filename to save the downloaded backup to
  *
  * [--file=<filename>]
  * : Select one of the files from the list subcommand. Only used for 'get'
  *
  * [--latest]
  * : If set the latest backup will be selected automatically
  *
  * [--keep-for]
  * : Number of days to keep this backup
  *
  * @subcommand backups
  *
  */
 public function backups($args, $assoc_args)
 {
     $action = array_shift($args);
     $site = $this->sites->get(Input::sitename($assoc_args));
     $env = Input::env($assoc_args, 'env');
     //Backward compatability supports "database" as a valid element value.
     if (isset($assoc_args['element']) && $assoc_args['element'] == 'database') {
         $assoc_args['element'] = 'db';
     }
     switch ($action) {
         case 'get':
             $file = Input::optional('file', $assoc_args, false);
             if ($file) {
                 $regex = sprintf("/%s_%s_\\d{4}-\\d{2}-\\d{2}T\\d{2}-\\d{2}-\\d{2}_UTC_(.*).tar.gz/", $site->get('name'), $env);
                 preg_match($regex, $file, $matches);
                 $element = $matches[1];
             } elseif (isset($assoc_args['element'])) {
                 $element = $assoc_args['element'];
             } else {
                 $element = Terminus::menu(array('code', 'files', 'db'), null, 'Select backup element', true);
                 if (!in_array($element, array('code', 'files', 'db'))) {
                     $this->failure('Invalid backup element specified.');
                 }
             }
             $latest = (bool) Input::optional('latest', $assoc_args, false);
             if (!in_array($element, array('code', 'files', 'db'))) {
                 $this->failure('Invalid backup element specified.');
             }
             $latest = Input::optional('latest', $assoc_args, false);
             $backups = $site->environments->get($env)->backups($element);
             if (empty($backups)) {
                 $this->failure('No backups available. Create one with `terminus site backup create --site={site} --env={env}`', array('site' => $site->get('name'), 'env' => $env));
             }
             //Ensure that that backups being presented for retrieval have finished
             $backups = array_filter($backups, function ($backup) {
                 return isset($backup->finish_time) && $backup->finish_time;
             });
             if ($latest) {
                 $backup = array_pop($backups);
             } elseif ($file) {
                 do {
                     try {
                         $candidate = array_pop($backups);
                     } catch (\Exception $e) {
                         $this->failure("{$file} is not a valid backup archive");
                     }
                     if ($candidate->filename == $file) {
                         $backup = $candidate;
                     }
                 } while (!isset($backup));
             }
             if (!isset($backup)) {
                 $menu = $folders = array();
                 foreach ($backups as $folder => $backup) {
                     if (!isset($backup->filename)) {
                         continue;
                     }
                     if (!isset($backup->folder)) {
                         $backup->folder = $folder;
                     }
                     $menu[] = $backup->filename;
                 }
                 $index = Terminus::menu($menu, null, 'Select backup');
                 $backup_elements = array_values($backups);
                 $backup = $backup_elements[$index];
             }
             if (empty($menu)) {
                 $this->failure('No backups available. Create one with `terminus site backup create --site={site} --env={env}`', array('site' => $site->get('name'), 'env' => $env));
             }
             $index = 0;
             if (!$latest) {
                 $index = Terminus::menu($menu, null, 'Select backup');
             }
             $bucket = $buckets[$index];
             $filename = $menu[$index];
             $url = $site->environments->get($env)->backupUrl($bucket, $element);
             if (isset($assoc_args['to'])) {
                 $target = str_replace('~', $_SERVER['HOME'], $assoc_args['to']);
                 if (is_dir($target)) {
                     $filename = Utils\getFilenameFromUrl($url->url);
                     $target = sprintf('%s/%s', $target, $filename);
                 }
                 $this->log()->info('Downloading ... please wait ...');
                 if ($this->download($url->url, $target)) {
                     $this->log()->info('Downloaded {target}', array('target' => $target));
                     return $target;
                 } else {
                     $this->failure('Could not download file');
                 }
             }
             $this->output()->outputValue($url->url, 'Backup URL');
             return $url->url;
             break;
         case 'load':
             $assoc_args['to'] = '/tmp';
             $assoc_args['element'] = 'database';
             if (isset($assoc_args['database'])) {
                 $database = $assoc_args['database'];
             } else {
                 $database = escapeshellarg(Terminus::prompt('Name of database to import to'));
             }
             if (isset($assoc_args['username'])) {
                 $username = $assoc_args['username'];
             } else {
                 $username = escapeshellarg(Terminus::prompt('Username'));
             }
             if (isset($assoc_args['password'])) {
                 $password = $assoc_args['password'];
             } else {
                 $password = escapeshellarg(Terminus::prompt('Password'));
             }
             exec('mysql -e "show databases"', $stdout, $exit);
             if ($exit != 0) {
                 $this->failure('MySQL does not appear to be installed on your server.');
             }
             $assoc_args['env'] = $env;
             $target = $this->backup(array('get'), $assoc_args);
             $target = '/tmp/' . Utils\getFilenameFromUrl($target);
             if (!file_exists($target)) {
                 $this->failure('Cannot read database file {target}', array('target' => $target));
             }
             $this->log()->info('Unziping database');
             exec("gunzip {$target}", $stdout, $exit);
             // trim the gz of the target
             $target = Utils\sqlFromZip($target);
             $target = escapeshellarg($target);
             exec("mysql {$database} -u {$username} -p'{$password}' < {$target}", $stdout, $exit);
             if ($exit != 0) {
                 $this->failure('Could not import database');
             }
             $this->log()->info('{target} successfully imported to {db}', array('target' => $target, 'db' => $database));
             return true;
             break;
         case 'create':
             if (!array_key_exists('element', $assoc_args)) {
                 $options = array('code', 'db', 'files', 'all');
                 $assoc_args['element'] = $options[Input::menu($options, 'all', 'Select element')];
             }
             $workflow = $site->environments->get($env)->createBackup($assoc_args);
             $workflow->wait();
             $this->workflowOutput($workflow);
             break;
         case 'list':
         default:
             $backups = $site->environments->get($env)->backups();
             //die(print_r($backups, true));
             $element_name = false;
             if (isset($assoc_args['element']) && $assoc_args['element'] != 'all') {
                 $element_name = $assoc_args['element'];
             }
             if ($element_name == 'db') {
                 $element_name = 'database';
             }
             $data = array();
             foreach ($backups as $id => $backup) {
                 if (!isset($backup->filename) || $element_name && !preg_match(sprintf('/_%s/', $element_name), $id)) {
                     continue;
                 }
                 $date = 'Pending';
                 if (isset($backup->finish_time)) {
                     $date = date('Y-m-d H:i:s', $backup->finish_time);
                 }
                 $size = 0;
                 if (isset($backup->size)) {
                     $size = $backup->size / 1048576;
                 }
                 if ($size > 0.1) {
                     $size = sprintf('%.1fMB', $size);
                 } elseif ($size > 0) {
                     $size = '0.1MB';
                 } else {
                     //0-byte backups should not be recommended for restoration
                     $size = 'Incomplete';
                 }
                 $data[] = array('file' => $backup->filename, 'size' => $size, 'date' => $date);
             }
             if (empty($data)) {
                 $this->log()->warning('No backups found.');
             }
             $this->output()->outputRecordList($data, array('file' => 'File', 'size' => 'Size', 'date' => 'Date'));
             return $data;
             break;
     }
 }
 function testOptionalReturnsDefaultFromFunction()
 {
     $default_null = Input::optional(array('key' => 'key', 'choices' => array('not' => 'me')));
     $this->assertEquals(null, $default_null);
 }
Exemple #9
0
 /**
  * Get, load, create, or list backup information
  *
  * ## OPTIONS
  *
  * <get|load|create|list>
  * : Function to run - get, load, create, or list
  *
  * [--site=<site>]
  * : Site to load
  *
  * [--env=<env>]
  * : Environment to load
  *
  * [--element=<code|files|db|all>]
  * : Element to download or create. *all* only used for 'create'
  *
  * [--to-directory=<directory>]
  * : Absolute path of directory to download the file
  *
  * [--latest]
  * : If set the latest backup will be selected automatically
  *
  * [--keep-for]
  * : Number of days to keep this backup
  *
  * @subcommand backups
  *
  */
 public function backups($args, $assoc_args)
 {
     $action = array_shift($args);
     $site = SiteFactory::instance(Input::sitename($assoc_args));
     $env = Input::env($assoc_args, 'env');
     switch ($action) {
         case 'get':
             //Backward compatability supports "database" as a valid element value.
             if (@$assoc_args['element'] == 'database') {
                 $assoc_args['element'] = 'db';
             }
             // prompt for backup type
             if (!($element = @$assoc_args['element'])) {
                 $element = Terminus::menu(array('code', 'files', 'db'), null, "Select type backup", TRUE);
             }
             if (!in_array($element, array('code', 'files', 'db'))) {
                 Terminus::error("Invalid backup element specified.");
             }
             $latest = Input::optional('latest', $assoc_args, false);
             $backups = $site->environment($env)->backups($element);
             // Ensure that that backups being presented for getting have finished
             $backups = array_filter($backups, function ($backup) {
                 return isset($backup->finish_time) && $backup->finish_time;
             });
             if ($latest) {
                 $backups = array(array_pop($backups));
             }
             if (empty($backups)) {
                 \Terminus::error('No backups available.');
             }
             $menu = $folders = array();
             // build a menu for selecting back ups
             foreach ($backups as $folder => $backup) {
                 if (!isset($backup->filename)) {
                     continue;
                 }
                 if (!isset($backup->folder)) {
                     $backup->folder = $folder;
                 }
                 $buckets[] = $backup->folder;
                 $menu[] = $backup->filename;
             }
             if (empty($menu)) {
                 Terminus::error("No backups available. Create one with `terminus site backup create --site=%s --env=%s`", array($site->getName(), $env));
             }
             $index = 0;
             if (!$latest) {
                 $index = Terminus::menu($menu, null, "Select backup");
             }
             $bucket = $buckets[$index];
             $filename = $menu[$index];
             $url = $site->environment($env)->backupUrl($bucket, $element);
             if (isset($assoc_args['to-directory'])) {
                 Terminus::line("Downloading ... please wait ...");
                 $filename = \Terminus\Utils\get_filename_from_url($url->url);
                 $target = sprintf("%s/%s", $assoc_args['to-directory'], $filename);
                 if (TerminusCommand::download($url->url, $target)) {
                     Terminus::success("Downloaded %s", $target);
                     return $target;
                 } else {
                     Terminus::error("Could not download file");
                 }
             }
             echo $url->url;
             return $url->url;
             break;
         case 'load':
             $assoc_args['to-directory'] = '/tmp';
             $assoc_args['element'] = 'database';
             $database = @$assoc_args['database'] ?: false;
             $username = @$assoc_args['username'] ?: false;
             $password = @$assoc_args['password'] ?: false;
             exec("mysql -e 'show databases'", $stdout, $exit);
             if (0 != $exit) {
                 Terminus::error("MySQL does not appear to be installed on your server.");
             }
             $assoc_args['env'] = $env;
             $target = $this->backup(array('get'), $assoc_args);
             $target = \Terminus\Utils\get_filename_from_url($target);
             $target = "/tmp/{$target}";
             if (!file_exists($target)) {
                 Terminus::error("Can't read database file %s", array($target));
             }
             Terminus::line("Unziping database");
             exec("gunzip {$target}", $stdout, $exit);
             // trim the gz of the target
             $target = Terminus\Utils\sql_from_zip($target);
             $target = escapeshellarg($target);
             if (!$database) {
                 $database = escapeshellarg(Terminus::prompt("Name of database to import to"));
             }
             if (!$username) {
                 $username = escapeshellarg(Terminus::prompt("Username"));
             }
             if (!$password) {
                 $password = escapeshellarg(Terminus::prompt("Password"));
             }
             exec("mysql {$database} -u {$username} -p'{$password}' < {$target}", $stdout, $exit);
             if (0 != $exit) {
                 Terminus::error("Could not import database");
             }
             Terminus::success("%s successfuly imported to %s", array($target, $database));
             return true;
             break;
         case 'create':
             if (!array_key_exists('element', $assoc_args)) {
                 $assoc_args['element'] = Input::menu(array('code', 'db', 'files', 'all'), 'all', "Select element");
             }
             $result = $site->environment($env)->createBackup($assoc_args);
             if ($result) {
                 Terminus::success("Created backup");
             } else {
                 Terminus::error("Couldn't create backup.");
             }
             break;
         case 'list':
         default:
             $backups = $site->environment($env)->backups();
             $element_name = isset($assoc_args['element']) && $assoc_args['element'] != 'all' ? $assoc_args['element'] : false;
             if ($element_name == 'db') {
                 $element_name = 'database';
             }
             $data = array();
             foreach ($backups as $id => $backup) {
                 if (!isset($backup->filename)) {
                     continue;
                 }
                 if ($element_name && !preg_match(sprintf('/backup_%s/', $element_name), $id)) {
                     continue;
                 }
                 $date = 'Pending';
                 if (isset($backup->finish_time)) {
                     $date = date("Y-m-d H:i:s", $backup->finish_time);
                 }
                 $size = $backup->size / 1024 / 1024;
                 if ($size > 0.1) {
                     $size = sprintf("%.1fMB", $size);
                 } elseif ($size > 0) {
                     $size = "0.1MB";
                 } else {
                     // 0-byte backups should not be recommended for restore
                     $size = "Incomplete";
                 }
                 $data[] = array($backup->filename, $size, $date);
             }
             if (empty($backups)) {
                 \Terminus::error("No backups found.");
                 return false;
             } else {
                 //munging data
                 $this->handleDisplay($data, $args, array('File', 'Size', 'Date'));
                 return $data;
             }
             break;
     }
 }
Exemple #10
0
 /**
  * Retrieves a single backup or downloads it as requested
  *
  * @params [array] $assoc_args Parameters and flags from the command line
  * @return [string] $url->url
  */
 private function getBackup($assoc_args)
 {
     $site = $this->sites->get(Input::sitename($assoc_args));
     $env = $site->environments->get(Input::env(array('args' => $assoc_args, 'site' => $site)));
     $file = Input::optional('file', $assoc_args, false);
     if ($file) {
         $backup = $env->backups->getBackupByFileName($file);
         $element = $backup->getElement();
     } else {
         $element = Input::backupElement(array('args' => $assoc_args));
         $latest = (bool) Input::optional('latest', $assoc_args, false);
         $backups = $env->backups->getFinishedBackups($element);
         if ($latest) {
             $backup = array_pop($backups);
         } else {
             $context = array('site' => $site->get('name'), 'env' => $env->get('id'));
             $backup = Input::backup(array('backups' => $backups, 'context' => $context));
         }
     }
     $url = $backup->getUrl();
     if (isset($assoc_args['to'])) {
         $target = str_replace('~', $_SERVER['HOME'], $assoc_args['to']);
         if (is_dir($target)) {
             $filename = Utils\getFilenameFromUrl($url);
             $target = sprintf('%s/%s', $target, $filename);
         }
         $this->log()->info('Downloading ... please wait ...');
         if (Request::download($url, $target)) {
             $this->log()->info('Downloaded {target}', compact('target'));
             return $target;
         } else {
             $this->failure('Could not download file');
         }
     }
     return $url;
 }
Exemple #11
0
 /**
  * Get, load, create, or list backup information
  *
  * ## OPTIONS
  *
  * <get|load|create|list>
  * : Function to run - get, load, create, or list
  *
  * [--site=<site>]
  * : Site to load
  *
  * [--env=<env>]
  * : Environment to load
  *
  * [--element=<code|files|db|all>]
  * : Element to download or create. *all* only used for 'create'
  *
  * [--to-directory=<directory>]
  * : Absolute path of directory to download the file
  *
  * [--latest]
  * : If set the latest backup will be selected automatically
  *
  * [--keep-for]
  * : Number of days to keep this backup
  *
  * @subcommand backups
  *
  */
 public function backups($args, $assoc_args)
 {
     $action = array_shift($args);
     $site = $this->sites->get(Input::sitename($assoc_args));
     $env = Input::env($assoc_args, 'env');
     //Backward compatability supports "database" as a valid element value.
     if (isset($assoc_args['element']) && $assoc_args['element'] == 'database') {
         $assoc_args['element'] = 'db';
     }
     switch ($action) {
         case 'get':
             if (isset($assoc_args['element'])) {
                 $element = $assoc_args['element'];
             } else {
                 $element = Terminus::menu(array('code', 'files', 'db'), null, 'Select backup element', true);
             }
             if (!in_array($element, array('code', 'files', 'db'))) {
                 Terminus::error('Invalid backup element specified.');
             }
             $latest = Input::optional('latest', $assoc_args, false);
             $backups = $site->environments->get($env)->backups($element);
             //Ensure that that backups being presented for retrieval have finished
             $backups = array_filter($backups, function ($backup) {
                 return isset($backup->finish_time) && $backup->finish_time;
             });
             if ($latest) {
                 $backups = array(array_pop($backups));
             }
             if (empty($backups)) {
                 \Terminus::error('No backups available.');
             }
             $menu = $folders = array();
             foreach ($backups as $folder => $backup) {
                 if (!isset($backup->filename)) {
                     continue;
                 }
                 if (!isset($backup->folder)) {
                     $backup->folder = $folder;
                 }
                 $buckets[] = $backup->folder;
                 $menu[] = $backup->filename;
             }
             if (empty($menu)) {
                 Terminus::error('No backups available. Create one with ' . '`terminus site backup create --site=%s --env=%s`', array($site->get('name'), $env));
             }
             $index = 0;
             if (!$latest) {
                 $index = Terminus::menu($menu, null, 'Select backup');
             }
             $bucket = $buckets[$index];
             $filename = $menu[$index];
             $url = $site->environments->get($env)->backupUrl($bucket, $element);
             if (isset($assoc_args['to-directory'])) {
                 Terminus::line('Downloading ... please wait ...');
                 $filename = \Terminus\Utils\get_filename_from_url($url->url);
                 $target = sprintf('%s/%s', $assoc_args['to-directory'], $filename);
                 if (TerminusCommand::download($url->url, $target)) {
                     Terminus::success('Downloaded %s', $target);
                     return $target;
                 } else {
                     Terminus::error('Could not download file');
                 }
             }
             Terminus::success($url->url);
             return $url->url;
             break;
         case 'load':
             $assoc_args['to-directory'] = '/tmp';
             $assoc_args['element'] = 'database';
             if (isset($assoc_args['database'])) {
                 $database = $assoc_args['database'];
             } else {
                 $database = escapeshellarg(Terminus::prompt('Name of database to import to'));
             }
             if (isset($assoc_args['username'])) {
                 $username = $assoc_args['username'];
             } else {
                 $username = escapeshellarg(Terminus::prompt('Username'));
             }
             if (isset($assoc_args['password'])) {
                 $password = $assoc_args['password'];
             } else {
                 $password = escapeshellarg(Terminus::prompt('Password'));
             }
             exec('mysql -e "show databases"', $stdout, $exit);
             if ($exit != 0) {
                 Terminus::error('MySQL does not appear to be installed on your server.');
             }
             $assoc_args['env'] = $env;
             $target = $this->backup(array('get'), $assoc_args);
             $target = '/tmp/' . \Terminus\Utils\get_filename_from_url($target);
             if (!file_exists($target)) {
                 Terminus::error('Cannot read database file %s', array($target));
             }
             Terminus::line('Unziping database');
             exec("gunzip {$target}", $stdout, $exit);
             // trim the gz of the target
             $target = Terminus\Utils\sql_from_zip($target);
             $target = escapeshellarg($target);
             exec("mysql {$database} -u {$username} -p'{$password}' < {$target}", $stdout, $exit);
             if ($exit != 0) {
                 Terminus::error('Could not import database');
             }
             Terminus::success('%s successfuly imported to %s', array($target, $database));
             return true;
             break;
         case 'create':
             if (!array_key_exists('element', $assoc_args)) {
                 $assoc_args['element'] = Input::menu(array('code', 'db', 'files', 'all'), 'all', 'Select element');
             }
             $workflow = $site->environments->get($env)->createBackup($assoc_args);
             $workflow->wait();
             $this->workflowOutput($workflow);
             break;
         case 'list':
         default:
             $backups = $site->environments->get($env)->backups();
             $element_name = false;
             if (isset($assoc_args['element']) && $assoc_args['element'] != 'all') {
                 $element_name = $assoc_args['element'];
             }
             if ($element_name == 'db') {
                 $element_name = 'database';
             }
             $data = array();
             foreach ($backups as $id => $backup) {
                 if (!isset($backup->filename) || $element_name && !preg_match(sprintf('/backup_%s/', $element_name), $id)) {
                     continue;
                 }
                 $date = 'Pending';
                 if (isset($backup->finish_time)) {
                     $date = date('Y-m-d H:i:s', $backup->finish_time);
                 }
                 $size = $backup->size / 1048576;
                 if ($size > 0.1) {
                     $size = sprintf('%.1fMB', $size);
                 } elseif ($size > 0) {
                     $size = '0.1MB';
                 } else {
                     //0-byte backups should not be recommended for restoration
                     $size = 'Incomplete';
                 }
                 $data[] = array('file' => $backup->filename, 'size' => $size, 'date' => $date);
             }
             if (empty($backups)) {
                 \Terminus::error('No backups found.');
                 return false;
             } else {
                 $this->outputter->outputRecordList($data, array('file' => 'File', 'size' => 'Size', 'date' => 'Date'));
                 return $data;
             }
             break;
     }
 }
Exemple #12
0
 /**
  * Update all dev sites with an available upstream update.
  *
  * ## OPTIONS
  *
  * [--report]
  * : If set output will contain list of sites and whether they are up-to-date
  *
  * [--upstream=<upstream>]
  * : Specify a specific upstream to check for updating.
  *
  * [--no-updatedb]
  * : Use flag to skip running update.php after the update has applied
  *
  * [--xoption=<theirs|ours>]
  * : Corresponds to git's -X option, set to 'theirs' by default
  *   -- https://www.kernel.org/pub/software/scm/git/docs/git-merge.html
  *
  * [--tag=<tag>]
  * : Tag to filter by
  *
  * [--org=<id>]
  * : Only necessary if using --tag. Organization which has tagged the site
  *
  * [--cached]
  * : Set to prevent rebuilding of sites cache
  *
  * @subcommand mass-update
  */
 public function massUpdate($args, $assoc_args)
 {
     // Ensure the sitesCache is up to date
     if (!isset($assoc_args['cached'])) {
         $this->sites->rebuildCache();
     }
     $upstream = Input::optional(array('key' => 'upstream', 'choices' => $assoc_args, 'default' => false));
     $data = array();
     $report = Input::optional(array('key' => 'report', 'choices' => $assoc_args, 'default' => false));
     $confirm = Input::optional(array('key' => 'confirm', 'choices' => $assoc_args, 'default' => false));
     $tag = Input::optional(array('key' => 'tag', 'choices' => $assoc_args, 'default' => false));
     $org = '';
     if ($tag) {
         $org = Input::orgId(array('args' => $assoc_args));
     }
     $sites = $this->sites->filterAllByTag($tag, $org);
     // Start status messages.
     if ($upstream) {
         $this->log()->info('Looking for sites using {upstream}.', compact('upstream'));
     }
     foreach ($sites as $site) {
         $context = array('site' => $site->get('name'));
         $site->fetch();
         $updates = $site->getUpstreamUpdates();
         if (!isset($updates->behind)) {
             // No updates, go back to start.
             continue;
         }
         // Check for upstream argument and site upstream URL match.
         $siteUpstream = $site->info('upstream');
         if ($upstream && isset($siteUpstream->url)) {
             if ($siteUpstream->url != $upstream) {
                 // Uptream doesn't match, go back to start.
                 continue;
             }
         }
         if ($updates->behind > 0) {
             $data[$site->get('name')] = array('site' => $site->get('name'), 'status' => 'Needs update');
             $env = $site->environments->get('dev');
             if ($env->getConnectionMode() == 'sftp') {
                 $message = '{site} has available updates, but is in SFTP mode.';
                 $message .= ' Switch to Git mode to apply updates.';
                 $this->log()->warning($message, $context);
                 $data[$site->get('name')] = array('site' => $site->get('name'), 'status' => 'Needs update - switch to Git mode');
                 continue;
             }
             $updatedb = !Input::optional(array('key' => 'updatedb', 'choices' => $assoc_args, 'default' => false));
             $xoption = !Input::optional(array('key' => 'xoption', 'choices' => $assoc_args, 'default' => 'theirs'));
             if (!$report) {
                 $message = 'Apply upstream updates to %s ';
                 $message .= '( run update.php:%s, xoption:%s ) ';
                 $confirmed = Input::confirm(array('message' => $message, 'context' => array($site->get('name'), var_export($updatedb, 1), var_export($xoption, 1)), 'exit' => false));
                 if (!$confirmed) {
                     continue;
                     // User says No, go back to start.
                 }
                 // Backup the DB so the client can restore if something goes wrong.
                 $this->log()->info('Backing up {site}.', $context);
                 $backup = $env->createBackup(array('element' => 'all'));
                 // Only continue if the backup was successful.
                 if ($backup) {
                     $this->log()->info('Backup of {site} created.', $context);
                     $this->log()->info('Updating {site}.', $context);
                     $response = $site->applyUpstreamUpdates($env->get('id'), $updatedb, $xoption);
                     $data[$site->get('name')]['status'] = 'Updated';
                     $this->log()->info('{site} is updated.', $context);
                 } else {
                     $data[$site->get('name')]['status'] = 'Backup failed';
                     $this->failure('There was a problem backing up {site}. Update aborted.', $context);
                 }
             }
         } else {
             if (isset($assoc_args['report'])) {
                 $data[$site->get('name')] = array('site' => $site->get('name'), 'status' => 'Up to date');
             }
         }
     }
     if (!empty($data)) {
         sort($data);
         $this->output()->outputRecordList($data);
     } else {
         $this->log()->info('No sites in need of updating.');
     }
 }
Exemple #13
0
 /**
  * Print and save drush aliases
  *
  * ## OPTIONS
  *
  * [--print]
  * : print aliases to screen
  *
  * [--location=<location>]
  * : specify the location of the alias file, default it ~/.drush/pantheon.drushrc.php
  *
  */
 public function aliases($args, $assoc_args)
 {
     $user = new User();
     $print = Input::optional('print', $assoc_args, false);
     $json = \Terminus::get_config('json');
     $location = Input::optional('location', $assoc_args, getenv("HOME") . '/.drush/pantheon.aliases.drushrc.php');
     $message = "Pantheon aliases updated.";
     if (!file_exists($location)) {
         $message = "Pantheon aliases created.";
     }
     $content = $user->getAliases();
     $h = fopen($location, 'w+');
     fwrite($h, $content);
     fclose($h);
     chmod($location, 0777);
     Logger::coloredOutput("%2%K{$message}%n");
     if ($json) {
         include $location;
         print \Terminus\Utils\json_dump($aliases);
     } elseif ($print) {
         print $content;
     }
 }