PageRenderTime 31ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 1ms

/php/commands/sites.php

https://gitlab.com/Blueprint-Marketing/cli
PHP | 380 lines | 216 code | 39 blank | 125 comment | 30 complexity | f635619723e0bd65a02d148bd47466fc MD5 | raw file
  1. <?php
  2. /**
  3. * Actions on multiple sites
  4. *
  5. */
  6. use Terminus\Utils;
  7. use Terminus\Organization;
  8. use Terminus\Upstreams;
  9. use Terminus\Session;
  10. use Terminus\SitesCache;
  11. use Terminus\Site;
  12. use Terminus\SiteFactory;
  13. use Terminus\Auth;
  14. use Terminus\Helpers\Input;
  15. use Terminus\Models\User;
  16. use Symfony\Component\Finder\SplFileInfo;
  17. use Terminus\Loggers\Regular as Logger;
  18. use Terminus\Workflow;
  19. class Sites_Command extends TerminusCommand {
  20. public $sitesCache;
  21. /**
  22. * Show a list of your sites on Pantheon
  23. * @package Terminus
  24. * @version 2.0
  25. */
  26. public function __construct() {
  27. parent::__construct();
  28. Auth::loggedIn();
  29. $this->sitesCache = new SitesCache();
  30. }
  31. /**
  32. * Show all sites user has access to
  33. * Note: because of the size of this call, it is cached
  34. * and also is the basis for loading individual sites by name
  35. *
  36. * [--team]
  37. * : filter sites you are a team member of
  38. *
  39. * [--org=<id>]
  40. * : filter sites you can access via the organization
  41. *
  42. * @subcommand list
  43. * @alias show
  44. */
  45. public function index($args, $assoc_args) {
  46. // Always fetch a fresh list of sites
  47. $this->sitesCache->rebuild();
  48. $cached_sites = $this->sitesCache->all();
  49. $rows = array_map(function($cached_site) {
  50. return array(
  51. 'name' => $cached_site['name'],
  52. 'id' => $cached_site['id'],
  53. 'service_level' => $cached_site['service_level'],
  54. 'framework' => $cached_site['framework'],
  55. 'created' => date('Y-m-d H:i:s', $cached_site['created']),
  56. 'memberships' => array_map(function($membership) {
  57. return $membership['name'];
  58. }, array_values($cached_site['memberships']))
  59. );
  60. }, array_values($cached_sites));
  61. if (isset($assoc_args['team'])) {
  62. $rows = array_filter($rows, function($site) {
  63. return in_array('Team', $site['memberships']);
  64. });
  65. }
  66. if (isset($assoc_args['org'])) {
  67. $org_id = $assoc_args['org'];
  68. $rows = array_filter($rows, function($site) use ($org_id) {
  69. $org_ids = array_keys($site['memberships']);
  70. return in_array($org_id, $org_ids);
  71. });
  72. }
  73. if (count($rows) == 0) {
  74. Terminus::log("You have no sites.");
  75. exit(0);
  76. }
  77. $this->handleDisplay($rows);
  78. }
  79. /**
  80. * Create a new site
  81. *
  82. * ## OPTIONS
  83. *
  84. * [--site=<site>]
  85. * : Name of the site to create (machine-readable)
  86. *
  87. * [--name=<name>]
  88. * : (deprecated) use --site instead
  89. *
  90. * [--label=<label>]
  91. * : Label for the site
  92. *
  93. * [--upstream=<upstreamid>]
  94. * : Specify the upstream upstream to use
  95. *
  96. * [--import=<url>]
  97. * : A url to import a valid archive
  98. *
  99. * [--org=<id>]
  100. * : UUID of organization into which to add this site
  101. *
  102. */
  103. public function create($args, $assoc_args) {
  104. $options = array();
  105. $options['label'] = Input::string($assoc_args, 'label', "Human-readable label for the site");
  106. $suggested_name = Utils\sanitize_name( $options['label'] );
  107. if (array_key_exists('name', $assoc_args)) {
  108. // Deprecated but kept for backwards compatibility
  109. $options['name'] = $assoc_args['name'];
  110. } elseif (array_key_exists('site', $assoc_args)) {
  111. $options['name'] = $assoc_args['site'];
  112. } elseif (isset($_SERVER['TERMINUS_SITE'])) {
  113. $options['name'] = $_SERVER['TERMINUS_SITE'];
  114. } else {
  115. $options['name'] = Input::string($assoc_args, 'site', "Machine name of the site; used as part of the default URL (if left blank will be $suggested_name)", $suggested_name);
  116. }
  117. if (isset($assoc_args['org'])) {
  118. $options['organization_id'] = Input::orgid($assoc_args, 'org', false);
  119. }
  120. if (!isset($assoc_args['import'])) {
  121. $upstream = Input::upstream($assoc_args, 'upstream');
  122. $options['upstream_id'] = $upstream->get('id');
  123. Terminus::line(sprintf("Creating new %s installation ... ", $upstream->get('longname')));
  124. }
  125. $workflow = Site::create($options);
  126. $workflow->wait();
  127. Terminus::success("Pow! You created a new site!");
  128. // Add Site to SitesCache
  129. $final_task = $workflow->get('final_task');
  130. $site = new Site($final_task->site_id);
  131. $site->fetch();
  132. $cache_membership = array(
  133. 'id' => $final_task->site_id,
  134. 'name' => $options['name'],
  135. 'created' => $site->attributes->created,
  136. 'service_level' => $site->attributes->service_level,
  137. 'framework' => $site->attributes->framework,
  138. );
  139. if ($org_id) {
  140. $org = new Organization($org_id);
  141. $cache_membership['membership'] = array(
  142. 'id' => $org_id,
  143. 'name' => $org->profile->name,
  144. 'type' => 'organization'
  145. );
  146. } else {
  147. $user_id = Session::getValue('user_uuid');
  148. $cache_membership['membership'] = array(
  149. 'id' => $user_id,
  150. 'name' => 'Team',
  151. 'type' => 'team'
  152. );
  153. }
  154. $sites_cache = new Terminus\SitesCache();
  155. $sites_cache->add($cache_membership);
  156. if (isset($assoc_args['import'])) {
  157. sleep(10); //To stop erroenous site-DNE errors
  158. Terminus::launch_self('site', array('import'), array(
  159. 'url' => $assoc_args['import'],
  160. 'site' => $options['name'],
  161. 'element' => 'all'
  162. ));
  163. } else {
  164. Terminus::launch_self('site', array('info'), array(
  165. 'site' => $options['name'],
  166. ));
  167. }
  168. return true;
  169. }
  170. /**
  171. * Import a new site
  172. * @package 2.0
  173. *
  174. * ## OPTIONS
  175. *
  176. * [--url=<url>]
  177. * : URL of archive to import
  178. *
  179. * [--name=<name>]
  180. * : (deprecated) use --site instead
  181. *
  182. * [--site=<site>]
  183. * : Name of the site to create (machine-readable)
  184. *
  185. * [--label=<label>]
  186. * : Label for the site
  187. *
  188. * [--org=<id>]
  189. * : UUID of organization into which to add this site
  190. *
  191. * @subcommand create-from-import
  192. */
  193. public function import($args, $assoc_args) {
  194. $url = Input::string($assoc_args, 'url', "URL of archive to import");
  195. if (!$url) {
  196. Terminus::error("Please enter a URL.");
  197. }
  198. $assoc_args['import'] = $url;
  199. unset($assoc_args['url']);
  200. Terminus::launch_self('sites', array('create'), $assoc_args);
  201. }
  202. /**
  203. * [Deprecated] Delete a site from pantheon; use `site delete` instead
  204. *
  205. * ## OPTIONS
  206. * [--site=<site>]
  207. * : ID of the site you want to delete
  208. *
  209. * [--force]
  210. * : to skip the confirmations
  211. */
  212. function delete($args, $assoc_args) {
  213. Terminus::launch_self('site', array('delete'), $assoc_args);
  214. }
  215. /**
  216. * Print and save drush aliases
  217. *
  218. * ## OPTIONS
  219. *
  220. * [--print]
  221. * : print aliases to screen
  222. *
  223. * [--location=<location>]
  224. * : Specify the the full path, including the filename, to the alias file you wish to create.
  225. * Without this option a default of '~/.drush/pantheon.drushrc.php' will be used.
  226. *
  227. */
  228. public function aliases($args, $assoc_args) {
  229. $user = new User(new stdClass(), array());
  230. $print = Input::optional('print', $assoc_args, false);
  231. $json = \Terminus::get_config('json');
  232. $location = Input::optional('location', $assoc_args, getenv("HOME").'/.drush/pantheon.aliases.drushrc.php');
  233. // Cannot provide just a directory
  234. if (is_dir($location)) {
  235. \Terminus::error("Please provide a full path with filename, e.g. %s/pantheon.aliases.drushrc.php", $location);
  236. exit(1);
  237. }
  238. $file_exists = file_exists($location);
  239. // Create the directory if it doesn't yet exist
  240. $dirname = dirname($location);
  241. if (!is_dir($dirname)) {
  242. mkdir($dirname, 0700, true);
  243. }
  244. $content = $user->getAliases();
  245. $h = fopen($location, 'w+');
  246. fwrite($h, $content);
  247. fclose($h);
  248. chmod($location, 0700);
  249. $message = $file_exists ? 'Pantheon aliases updated' : 'Pantheon aliases created';
  250. Logger::coloredOutput("%2%K$message%n");
  251. if ($json) {
  252. include $location;
  253. print \Terminus\Utils\json_dump($aliases);
  254. } elseif ($print) {
  255. print $content;
  256. }
  257. }
  258. /**
  259. * Update alls dev sites with an available upstream update.
  260. *
  261. * ## OPTIONS
  262. *
  263. * [--report]
  264. * : If set output will contain list of sites and whether they are up-to-date
  265. *
  266. * [--upstream=<upstream>]
  267. * : Specify a specific upstream to check for updating.
  268. *
  269. * [--no-updatedb]
  270. * : Use flag to skip running update.php after the update has applied
  271. *
  272. * [--xoption=<theirs|ours>]
  273. * : Corresponds to git's -X option, set to 'theirs' by default -- https://www.kernel.org/pub/software/scm/git/docs/git-merge.html
  274. *
  275. * @subcommand mass-update
  276. */
  277. public function mass_update($args, $assoc_args) {
  278. // Ensure the sitesCache is up to date
  279. $this->sitesCache->rebuild();
  280. $sites_cache = $this->sitesCache->all();
  281. $env = 'dev';
  282. $upstream = Input::optional('upstream', $assoc_args, false);
  283. $data = array();
  284. $report = Input::optional('report', $assoc_args, false);
  285. $confirm = Input::optional('confirm', $assoc_args, false);
  286. // Start status messages.
  287. if($upstream) Terminus::line('Looking for sites using '.$upstream.'.');
  288. foreach($sites_cache as $site_cache ) {
  289. $site = new Site($site_cache['id']);
  290. $site->fetch();
  291. $updates = $site->getUpstreamUpdates();
  292. if (!isset($updates->behind)) {
  293. // No updates, go back to start.
  294. continue;
  295. }
  296. // Check for upstream argument and site upstream URL match.
  297. $siteUpstream = $site->info('upstream');
  298. if ( $upstream AND isset($siteUpstream->url)) {
  299. if($siteUpstream->url <> $upstream ) {
  300. // Uptream doesn't match, go back to start.
  301. continue;
  302. }
  303. }
  304. if( $updates->behind > 0 ) {
  305. $data[$site->getName()] = array('site'=> $site->getName(), 'status' => "Needs update");
  306. $updatedb = !Input::optional($assoc_args, 'updatedb', false);
  307. $xoption = Input::optional($assoc_args, 'xoption', 'theirs');
  308. if (!$report) {
  309. $confirmed = Input::yesno("Apply upstream updates to %s ( run update.php:%s, xoption:%s ) ", array($site->getName(), var_export($update,1), var_export($xoption,1)));
  310. if(!$confirmed) continue; // User says No, go back to start.
  311. // Backup the DB so the client can restore if something goes wrong.
  312. Terminus::line('Backing up '.$site->getName().'.');
  313. $backup = $site->environment('dev')->createBackup(array('element'=>'all'));
  314. // Only continue if the backup was successful.
  315. if($backup) {
  316. Terminus::success("Backup of ".$site->getName()." created.");
  317. Terminus::line('Updating '.$site->getName().'.');
  318. // Apply the update, failure here would trigger a guzzle exception so no need to validate success.
  319. $response = $site->applyUpstreamUpdates($env, $updatedb, $xoption);
  320. $data[$site->getName()]['status'] = 'Updated';
  321. Terminus::success($site->getName().' is updated.');
  322. } else {
  323. $data[$site->getName()]['status'] = 'Backup failed';
  324. Terminus::error('There was a problem backing up '.$site->getName().'. Update aborted.');
  325. }
  326. }
  327. } else {
  328. if (isset($assoc_args['report'])) {
  329. $data[$site->getName()] = array('site'=> $site->getName(), 'status' => "Up to date");
  330. }
  331. }
  332. }
  333. if (!empty($data)) {
  334. sort($data);
  335. $this->handleDisplay($data);
  336. } else {
  337. Terminus::line('No sites in need up updating.');
  338. }
  339. }
  340. }
  341. Terminus::add_command( 'sites', 'Sites_Command' );