/** * Invoke `wp` commands on a Pantheon development site * * <commands>... * : The WP-CLI commands you intend to run. * * [--<flag>=<value>] * : Additional WP-CLI flag(s) to pass in to the command. * * [--site=<site>] * : The name (DNS shortname) of your site on Pantheon. * * [--env=<environment>] * : Your Pantheon environment. Default: dev * */ function __invoke($args, $assoc_args) { $environment = Input::env($assoc_args); $sites = new Sites(); $site = $sites->get(Input::sitename($assoc_args)); if (!$site) { Terminus::error("Command could not be completed. Unknown site specified."); exit; } # see https://github.com/pantheon-systems/titan-mt/blob/master/dashboardng/app/workshops/site/models/environment.coffee $server = array('user' => "{$environment}.{$site->get('id')}", 'host' => "appserver.{$environment}.{$site->get('id')}.drush.in", 'port' => '2222'); if (strpos(TERMINUS_HOST, 'onebox') !== FALSE) { $server['user'] = "******"; $server['host'] = TERMINUS_HOST; } # Sanitize assoc args so we don't try to pass our own flags. # TODO: DRY this out? unset($assoc_args['site']); if (isset($assoc_args['env'])) { unset($assoc_args['env']); } # Create user-friendly output $command = implode($args, ' '); $flags = ''; foreach ($assoc_args as $k => $v) { if (isset($v) && (string) $v != '') { $flags .= "--{$k}=" . escapeshellarg($v) . ' '; } else { $flags .= "--{$k} "; } } $this->logger->info("Running wp %s %s on %s-%s", array($command, $flags, $site->get('name'), $environment)); $this->send_command($server, 'wp', $args, $assoc_args); }
/** * List an organizations sites * * ## OPTIONS * * [--org=<org>] * : Organization name or Id * * [--add=<site>] * : Site to add to organization * * [--remove=<site>] * : Site to remove from organization * * @subcommand sites * */ public function sites($args, $assoc_args) { $orgs = array(); $user = new User(); foreach ($user->organizations() as $id => $org) { $orgs[$id] = $org->name; } if (!isset($assoc_args['org']) or empty($assoc_args['org'])) { $selected_org = Terminus::menu($orgs, false, "Choose an organization"); } else { $selected_org = $assoc_args['org']; } $org = new Organization($selected_org); if (isset($assoc_args['add'])) { $add = SiteFactory::instance(Input::site($assoc_args, 'add')); Terminus::confirm("Are you sure you want to add %s to %s ?", $assoc_args, array($add->getName(), $org->name)); $org->addSite($add); Terminus::success("Added site!"); return true; } if (isset($assoc_args['remove'])) { $remove = SiteFactory::instance(Input::site($assoc_args, 'remove')); Terminus::confirm("Are you sure you want to remove %s to %s ?", $assoc_args, array($remove->getName(), $org->name)); $org->removeSite($remove); Terminus::success("Removed site!"); return true; } $sites = $org->getSites(); $data = array(); foreach ($sites as $site) { $data[] = array('name' => $site->site->name, 'service level' => isset($site->site->service_level) ? $site->site->service_level : '', 'framework' => isset($site->site->framework) ? $site->site->framework : '', 'created' => date('Y-m-d H:i:s', $site->site->created)); } $this->handleDisplay($data); }
/** * Make a request to the Pantheon API * * @param [string] $realm Permissions realm for data request (e.g. user, * site organization, etc. Can also be "public" to simply pull read-only * data that is not privileged. * @param [string] $uuid The UUID of the item in the realm to access * @param [string] $path API path (URL) * @param [string] $method HTTP method to use * @param [mixed] $options A native PHP data structure (e.g. int, string, * array, or stdClass) to be sent along with the request * @return [array] $data */ public static function request($realm, $uuid, $path = false, $method = 'GET', $options = null) { if (!in_array($realm, array('login', 'user', 'public'))) { Auth::loggedIn(); } try { $cache = Terminus::get_cache(); if (!in_array($realm, array('login', 'user'))) { $options['cookies'] = array('X-Pantheon-Session' => Session::getValue('session')); $options['verify'] = false; } $url = Endpoint::get(array('realm' => $realm, 'uuid' => $uuid, 'path' => $path)); if (Terminus::get_config('debug')) { Terminus::log('debug', 'Request URL: ' . $url); } $resp = Request::send($url, $method, $options); $json = $resp->getBody(true); $data = array('info' => $resp->getInfo(), 'headers' => $resp->getRawHeaders(), 'json' => $json, 'data' => json_decode($json), 'status_code' => $resp->getStatusCode()); return $data; } catch (Guzzle\Http\Exception\BadResponseException $e) { $response = $e->getResponse(); throw new TerminusException($response->getBody(true)); } catch (Guzzle\Http\Exception\HttpException $e) { $request = $e->getRequest(); $sanitized_request = TerminusCommand::stripSensitiveData((string) $request, TerminusCommand::$blacklist); throw new TerminusException('API Request Error. {msg} - Request: {req}', array('req' => $sanitized_request, 'msg' => $e->getMessage())); } catch (Exception $e) { throw new TerminusException('API Request Error: {msg}', array('msg' => $e->getMessage())); } }
protected function _url($args, $callback) { foreach ($args as $obj_id) { $object = $this->fetcher->get_check($obj_id); \Terminus::line($callback($object->{$this->obj_id_key})); } }
/** * List an organization's sites * * ## OPTIONS * * [--org=<id>] * : Organization id * * [--tag=<tag>] * : Tag name to filter sites list by * * [--add=<site>] * : Site to add to organization * * [--remove=<site>] * : Site to remove from organization * * @subcommand sites * */ public function sites($args, $assoc_args) { $org_id = Input::orgid($assoc_args, 'org', null, array('allow_none' => false)); $org = new Organization($org_id); if (isset($assoc_args['add'])) { $add = SiteFactory::instance(Input::sitename($assoc_args, 'add')); Terminus::confirm("Are you sure you want to add %s to %s ?", $assoc_args, array($add->getName(), $org->name)); $org->addSite($add); Terminus::success("Added site!"); return true; } if (isset($assoc_args['remove'])) { $remove = SiteFactory::instance(Input::sitename($assoc_args, 'remove')); Terminus::confirm("Are you sure you want to remove %s to %s ?", $assoc_args, array($remove->getName(), $org->name)); $org->removeSite($remove); Terminus::success("Removed site!"); return true; } $org->siteMemberships->fetch(); $memberships = $org->siteMemberships->all(); foreach ($memberships as $membership) { if (isset($assoc_args['tag']) && !in_array($assoc_args['tag'], $membership->get('tags'))) { continue; } $site = $membership->get('site'); $data[] = array('name' => $site->name, 'id' => $site->id, 'service_level' => $site->service_level, 'framework' => $site->framework, 'created' => date('Y-m-d H:i:s', $site->created), 'tags' => $membership->get('tags')); } $this->handleDisplay($data); }
/** * Log in as a user * * ## OPTIONS * [<email>] * : Email address to log in as. * * [--password=<value>] * : Log in non-interactively with this password. Useful for automation. * * [--machine-token=<value>] * : Authenticate using an Auth0 token * * [--debug] * : dump call information when logging in. */ public function login($args, $assoc_args) { // Try to login using a machine token, if provided. if (isset($assoc_args['machine-token']) || empty($args) && isset($_SERVER['TERMINUS_MACHINE_TOKEN'])) { $token = $_SERVER['TERMINUS_MACHINE_TOKEN']; if (isset($assoc_args['machine-token'])) { $token = $assoc_args['machine-token']; } $this->auth->logInViaMachineToken($token); } else { // Otherwise, do a normal email/password-based login. if (empty($args)) { if (isset($_SERVER['TERMINUS_USER'])) { $email = $_SERVER['TERMINUS_USER']; } else { $email = Terminus::prompt('Your email address?', null); } } else { $email = $args[0]; } if (isset($assoc_args['password'])) { $password = $assoc_args['password']; } else { $password = Terminus::promptSecret('Your dashboard password (input will not be shown)'); } $this->auth->logInViaUsernameAndPassword($email, $password); } $this->log()->debug(get_defined_vars()); Terminus::launchSelf('art', array('fist')); }
protected function send_command($server, $remote_exec, $args, $assoc_args) { # unset CLI args unset($assoc_args['site']); $remote_cmd = $remote_exec . ' '; foreach ($args as $arg) { $remote_cmd .= escapeshellarg($arg) . ' '; } foreach ($assoc_args as $key => $value) { if ($value != 1) { $remote_cmd .= ' --' . $key . '=' . escapeshellarg($value); } else { $remote_cmd .= ' --' . $key; } } $cmd = 'ssh -T ' . $server['user'] . '@' . $server['host'] . ' -p ' . $server['port'] . ' -o "AddressFamily inet"' . " " . escapeshellarg($remote_cmd); if (\Terminus::get_config('silent')) { ob_start(); } passthru($cmd, $exit_code); if (\Terminus::get_config('silent')) { $this->logger->info(ob_get_clean()); } if ($exit_code == 255) { $this->logger->error("Failed to connect. Check your credentials, and that you are specifying a valid environment."); } return $exit_code; }
/** * Invoke `drush` commands on a Pantheon development site * * <commands>... * : The Drush commands you intend to run. * * [--<flag>=<value>] * : Additional Drush flag(s) to pass in to the command. * * [--site=<site>] * : The name (DNS shortname) of your site on Pantheon. * * [--env=<environment>] * : Your Pantheon environment. Default: dev * */ function __invoke($args, $assoc_args) { $environment = Input::env($assoc_args); $sites = new Sites(); $site = $sites->get(Input::sitename($assoc_args)); if (!$site) { Terminus::error("Command could not be completed. Unknown site specified."); exit; } $server = array('user' => "{$environment}.{$site->get('id')}", 'host' => "appserver.{$environment}.{$site->get('id')}.drush.in", 'port' => '2222'); if (strpos(TERMINUS_HOST, 'onebox') !== FALSE) { $server['user'] = "******"; $server['host'] = TERMINUS_HOST; } # Sanitize assoc args so we don't try to pass our own flags. # TODO: DRY this out? unset($assoc_args['site']); if (isset($assoc_args['env'])) { unset($assoc_args['env']); } # Create user-friendly output $command = implode($args, ' '); $flags = ''; foreach ($assoc_args as $k => $v) { if (isset($v) && (string) $v != '') { $flags .= "--{$k}={$v} "; } else { $flags .= "--{$k} "; } } $this->logger->info("Running drush %s %s on %s-%s", array($command, $flags, $site->get('name'), $environment)); $this->send_command($server, 'drush', $args, $assoc_args); }
public function __construct($filename, $delimiter = ',') { $this->filePointer = fopen($filename, 'r'); if (!$this->filePointer) { \Terminus::error(sprintf('Could not open file: %s', $filename)); } $this->delimiter = $delimiter; }
public function testRunCommand() { $runner = \Terminus::getRunner(); $this->assertInstanceOf('Terminus\\Runner', $runner); $args = array('site'); $assoc_args = array('site' => 'phpunittest'); $return = $runner->runCommand($args, $assoc_args); $this->assertNull($return); }
/** * View Pantheon artwork * * ## Options * * fist * * unicorn * * druplicon * * wordpress */ function __invoke($args, $assoc_args) { $artwork = array_shift($args) ?: array_rand($this->works); if (!empty($artwork) && array_key_exists($artwork, $this->works)) { echo Terminus::colorize("%g" . base64_decode($this->works[$artwork]) . "%n") . "\n"; } else { throw new TerminusException("No formula for requested artwork"); } }
private function init_config() { $configurator = \Terminus::get_configurator(); list($args, $assoc_args, $runtime_config) = $configurator->parse_args(array_slice($GLOBALS['argv'], 1)); $this->arguments = $args; $this->assoc_args = $assoc_args; $configurator->merge_array($runtime_config); list($this->config, $this->extra_config) = $configurator->to_array(); }
/** * Commands specific to an environment * * <commands>... * [--site=<value>] * : specify the site on which the command should be performed * [--env=<value>] * : Specificy the environment of a site previously set with --site= * * [--<flag>=<value>] * : Additional argument flag(s) to pass in to the command. */ function __invoke(array $args, array $assoc_args) { if (empty($args)) { Terminus::error("You need to specify a task to perform, site and environment on which to perform."); } else { $this->_handleFuncArg($args, $assoc_args); $this->_handleSiteArg($args, $assoc_args); } $this->_execute($args, $assoc_args); }
/** * @vcr utils#checkCurrentVersion */ public function testCheckForUpdate() { $log_file = getLogFileName(); setOutputDestination($log_file); Terminus::getCache()->putData('latest_release', ['check_date' => strtotime('8 days ago')]); Utils\checkForUpdate(); $file_contents = explode("\n", file_get_contents($log_file)); $this->assertFalse(strpos(array_pop($file_contents), 'An update to Terminus is available.')); resetOutputDestination($log_file); }
static function getArgsKey($args) { // strip UUIDs $string = preg_replace('#https://dashboard.getpantheon.com/api/(sites|users|ogranizations)\\/(.*)\\/(.+)$#s', '$1/$3', $args[0]); $key = sprintf('%s%s', $args[1], strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '-', $string)))); if (\Terminus::get_config('debug')) { \Terminus\Loggers\Regular::debug(var_export($args, 1)); \Terminus\Loggers\Regular::debug($key); } return $key; }
function show_usage() { $methods = $this->get_subcommands(); $i = 0; foreach ($methods as $name => $subcommand) { $prefix = 0 == $i++ ? 'usage: ' : ' or: '; \Terminus::line($subcommand->get_usage($prefix)); } \Terminus::line(); \Terminus::line("See 'terminus help {$this->name} <command>' for more information on a specific command."); }
/** * @param array The raw CLI arguments * @return array The list of found items */ public function get_many($args) { $items = array(); foreach ($args as $arg) { $item = $this->get($arg); if ($item) { $items[] = $item; } else { \Terminus::warning(sprintf($this->msg, $arg)); } } return $items; }
/** * The License singleton * * @var License */ function __construct() { $whmcs = Application::getinstance(); $this->licensekey = $whmcs->get_license_key(); $this->localkey = $whmcs->get_config('License'); $this->salt = sha1('WHMCS' . $whmcs->get_config('Version') . 'TFB' . $whmcs->get_hash()); $this->date = date('Ymd'); $this->decodeLocalOnce(); if (isset($_GET['forceremote'])) { $this->forceRemoteCheck(); Terminus::getinstance()->doExit(); } }
private static function show_help($command) { $out = self::get_initial_markdown($command); $longdesc = $command->get_longdesc(); if ($longdesc) { $out .= wordwrap($longdesc, 79) . "\n"; } // section headers $out = preg_replace('/^## ([A-Z ]+)/m', Terminus::colorize('%9\\1%n'), $out); // definition lists $out = preg_replace_callback('/([^\\n]+)\\n: (.+?)(\\n\\n|$)/s', array(__CLASS__, 'rewrap_param_desc'), $out); $out = str_replace("\t", ' ', $out); self::pass_through_pager($out); }
public static function send($url, $method, $data = array()) { // create a new Guzzle\Http\Client $browser = new Browser(); $browser->setUserAgent(self::userAgent()); $options = array(); $options['allow_redirects'] = @$data['allow_redirects'] ?: false; $options['json'] = @$data['json'] ?: false; if (@$data['body']) { $options['body'] = $data['body']; if (\Terminus::get_config("debug")) { \Terminus\Loggers\Regular::debug($data['body']); } } $options['verify'] = false; $request = $browser->createRequest($method, $url, null, null, $options); if (!empty($data['postdata'])) { foreach ($data['postdata'] as $k => $v) { $request->setPostField($k, $v); } } if (!empty($data['cookies'])) { foreach ($data['cookies'] as $k => $v) { $request->addCookie($k, $v); } } if (!empty($data['headers'])) { foreach ($data['headers'] as $k => $v) { $request->setHeader($k, $v); } } if (\Terminus::get_config("debug")) { $debug = "#### REQUEST ####" . PHP_EOL; $debug .= $request->getRawHeaders(); \Terminus\Loggers\Regular::debug($debug); if (isset($data['body'])) { \Terminus\Loggers\Regular::debug($data['body']); } } if (getenv("BUILD_FIXTURES")) { Fixtures::put("request_headers", $request->getRawHeaders()); } $response = $request->send(); if (getenv("BUILD_FIXTURES")) { Fixtures::put(array($url, $method, $data), $response); } return $response; }
/** * Return all environments for a site */ public function environments() { $cache = \Terminus::get_cache(); if (empty($this->environments)) { if (!($environments = $cache->get_data("environments:{$this->id}"))) { $results = \Terminus_Command::request("sites", $this->getId(), "environments", "GET"); $environments = $results['data']; $cache->put_data("environments:{$this->id}", $environments); } $this->environments = $environments; } // instantiate local objects foreach ($this->environments as $name => $env) { $this->environments->{$name} = EnvironmentFactory::load($this, $name, array('hydrate_with' => $env)); } return $this->environments; }
public static function send($url, $method, $data = array()) { // create a new Guzzle\Http\Client $browser = new Browser(); $browser->setUserAgent(self::userAgent()); $options = array('allow_redirects' => false, 'verify' => false, 'json' => false); if (isset($data['allow_redirects'])) { $options['allow_redirects'] = $data['allow_redirects']; } if (isset($data['json'])) { $options['json'] = $data['json']; } if (isset($data['body']) && $data['body']) { $options['body'] = $data['body']; if (\Terminus::get_config('debug')) { \Terminus::log('debug', $data['body']); } } $request = $browser->createRequest($method, $url, null, null, $options); if (!empty($data['postdata'])) { foreach ($data['postdata'] as $k => $v) { $request->setPostField($k, $v); } } if (!empty($data['cookies'])) { foreach ($data['cookies'] as $k => $v) { $request->addCookie($k, $v); } } if (!empty($data['headers'])) { foreach ($data['headers'] as $k => $v) { $request->setHeader($k, $v); } } if (\Terminus::get_config("debug")) { $debug = "#### REQUEST ####" . PHP_EOL; $debug .= $request->getRawHeaders(); \Terminus::log('debug', $debug); if (isset($data['body'])) { \Terminus::log('debug', $data['body']); } } $response = $request->send(); return $response; }
function feedback($string) { if (isset($this->upgrader->strings[$string])) { $string = $this->upgrader->strings[$string]; } if (strpos($string, '%') !== false) { $args = func_get_args(); $args = array_splice($args, 1); if (!empty($args)) { $string = vsprintf($string, $args); } } if (empty($string)) { return; } $string = str_replace('…', '...', strip_tags($string)); \Terminus::line($string); }
function get_longdesc() { $binding = array(); foreach (\Terminus::get_configurator()->get_spec() as $key => $details) { if ($details['runtime'] === false || isset($details['deprecated']) || isset($details['hidden'])) { continue; } if ($details['runtime']) { $synopsis = "--[no-]{$key}"; } else { $synopsis = "--{$key}" . $details['runtime']; } $binding['parameters'][] = array('synopsis' => $synopsis, 'desc' => $details['desc']); } if ((bool) \Terminus::get_config('json')) { return $binding; } return Utils\mustache_render('man-params.mustache', $binding); }
/** * Waits on this workflow to finish * * @return [Workflow] $this */ public function wait() { while (!$this->isFinished()) { $this->fetch(); sleep(3); print "."; } if ($this->isSuccessful()) { return $this; } else { $final_task = $this->get('final_task'); if ($final_task != null && !empty($final_task->messages)) { foreach ($final_task->messages as $data => $message) { \Terminus::error(sprintf('[%s] %s', $message->level, $message->message)); exit; } } } }
public function invalid_positionals($args) { $positionals = $this->query_spec(array('type' => 'positional')); for ($i = 0; $i < count($args); $i++) { if (!isset($positionals[$i]['token'])) { continue; } $token = preg_replace('#\\[?\\<([a-zA-Z].*)\\>\\]?.*#s', '$1', $positionals[$i]['token']); if ("commands" == trim($token) || "email" == trim($token)) { // we exit here because the wp and drush commands need to not have validation running since their commands are dependent on their respective code bases. return false; } $regex = "#^({$token})\$#s"; \Terminus::log('debug', "Positional match {$regex}"); if (!preg_match($regex, $args[$i])) { return $args[$i]; } } return false; }
protected function send_command($server, $remote_exec, $args, $assoc_args) { # unset CLI args unset($assoc_args['site']); $remote_cmd = $remote_exec . ' '; $remote_cmd .= implode(' ', $args); foreach ($assoc_args as $key => $value) { if ($value != 1) { $remote_cmd .= ' --' . $key . '=' . $value; } else { $remote_cmd .= ' --' . $key; } } $cmd = 'ssh -T ' . $server['user'] . '@' . $server['host'] . ' -p ' . $server['port'] . ' -o "AddressFamily inet"' . " '" . $remote_cmd . "'"; passthru($cmd, $exit_code); if ($exit_code == 255) { \Terminus::error("Failed to connect. Check your credentials, and that you are specifying a valid environment."); } return $exit_code; }
/** * Waits on this workflow to finish * * @return [Workflow] $this */ public function wait() { while (!$this->isFinished()) { $this->fetch(); sleep(3); // TODO: output this to stdout so that it doesn't get mixed with any actual output. // We can't use the logger here because that might be redirected to a log-file and each line is timestamped. \Terminus::out("."); } // TODO: output this to stdout so that it doesn't get mixed with any actual output. \Terminus::line(); if ($this->isSuccessful()) { return $this; } else { $final_task = $this->get('final_task'); if ($final_task != null && !empty($final_task->messages)) { foreach ($final_task->messages as $data => $message) { throw new TerminusException($message->message); } } } }
/** * List an organization's sites * * ## OPTIONS * * [--org=<id|name>] * : Organization UUID or name * * [--tag=<tag>] * : Tag name to filter sites list by * * [--add=<site>] * : Site to add to organization * * [--remove=<site>] * : Site to remove from organization * * @subcommand sites * */ public function sites($args, $assoc_args) { $org_id = Input::orgid($assoc_args, 'org', null, array('allow_none' => false)); $orgs = new UserOrganizationMemberships(); $org = $orgs->get($org_id); $memberships = $org->site_memberships; if (isset($assoc_args['add'])) { $site = $this->sites->get(Input::sitename($assoc_args, 'add')); Terminus::confirm('Are you sure you want to add %s to %s ?', $assoc_args, array($site->get('name'), $org->get('name'))); $memberships->addMember($site); Terminus::success('Added site!'); return true; } if (isset($assoc_args['remove'])) { $site_id = $assoc_args['remove']; $member = $memberships->get($assoc_args['remove']); $site = $member->get('site'); Terminus::confirm('Are you sure you want to remove %s from %s ?', $assoc_args, array($site->name, $org->get('name'))); $member->removeMember(); Terminus::success('Removed site!'); return true; } $memberships = $org->getSites(); foreach ($memberships as $membership) { if (isset($assoc_args['tag']) && !in_array($assoc_args['tag'], $membership->get('tags'))) { continue; } $site = $membership->get('site'); $data_array = array('name' => null, 'id' => null, 'service_level' => null, 'framework' => null, 'created' => null, 'tags' => $membership->get('tags')); foreach ($data_array as $key => $value) { if ($value == null && isset($site->{$key})) { $data_array[$key] = $site->{$key}; } } $data_array['created'] = date('Y-m-dTH:i:s', $data_array['created']); $data[] = $data_array; } $this->outputter->outputRecordList($data); }
/** * Invoke `drush` commands on a Pantheon development site * * <commands>... * : The Drush commands you intend to run. * * [--<flag>=<value>] * : Additional Drush flag(s) to pass in to the command. * * [--site=<site>] * : The name (DNS shortname) of your site on Pantheon. * * [--env=<environment>] * : Your Pantheon environment. Default: dev * */ public function __invoke($args, $assoc_args) { $command = implode($args, ' '); $this->checkCommand($command); $sites = new Sites(); $assoc_args['site'] = Input::sitename($assoc_args); $site = $sites->get($assoc_args['site']); if (!$site) { $this->failure('Command could not be completed. Unknown site specified.'); } $assoc_args['env'] = $environment = Input::env($assoc_args); $server = $this->getAppserverInfo(array('site' => $site->get('id'), 'environment' => $environment)); # Sanitize assoc args so we don't try to pass our own flags. # TODO: DRY this out? if (isset($assoc_args['site'])) { unset($assoc_args['site']); } if (isset($assoc_args['env'])) { unset($assoc_args['env']); } # Create user-friendly output $flags = ''; foreach ($assoc_args as $k => $v) { if (isset($v) && (string) $v != '') { $flags .= "--{$k}={$v} "; } else { $flags .= "--{$k} "; } } if (in_array(Terminus::getConfig('format'), array('bash', 'json', 'silent'))) { $assoc_args['pipe'] = 1; } $this->log()->info("Running drush {cmd} {flags} on {site}-{env}", array('cmd' => $command, 'flags' => $flags, 'site' => $site->get('name'), 'env' => $environment)); $result = $this->sendCommand($server, 'drush', $args, $assoc_args); if (Terminus::getConfig('format') != 'normal') { $this->output()->outputRecordList($result); } }