/** * @param string $property * @param string $value * @param Environment $environment * * @return int */ protected function setProperty($property, $value, Environment $environment) { if (!$this->validateValue($property, $value)) { return 1; } $type = $this->getType($property); if ($type === 'boolean' && $value === 'false') { $value = false; } settype($value, $type); $currentValue = $environment->getProperty($property, false); if ($currentValue === $value) { $this->stdErr->writeln("Property <info>{$property}</info> already set as: " . $this->formatter->format($environment->getProperty($property, false), $property)); return 0; } $environment->update(array($property => $value)); $this->stdErr->writeln("Property <info>{$property}</info> set to: " . $this->formatter->format($environment[$property], $property)); $rebuildProperties = array('enable_smtp', 'restrict_robots'); if (in_array($property, $rebuildProperties) && !$environment->getLastActivity()) { $this->rebuildWarning(); } // Refresh the stored environments. $this->getEnvironments($this->getSelectedProject(), true); return 0; }
/** * @param string $property * @param string $value * @param Environment $environment * @param bool $noWait * * @return int */ protected function setProperty($property, $value, Environment $environment, $noWait) { if (!$this->validateValue($property, $value)) { return 1; } $type = $this->getType($property); if ($type === 'boolean' && $value === 'false') { $value = false; } settype($value, $type); $currentValue = $environment->getProperty($property, false); if ($currentValue === $value) { $this->stdErr->writeln("Property <info>{$property}</info> already set as: " . $this->formatter->format($environment->getProperty($property, false), $property)); return 0; } $result = $environment->update([$property => $value]); $this->stdErr->writeln("Property <info>{$property}</info> set to: " . $this->formatter->format($environment->{$property}, $property)); $this->clearEnvironmentsCache(); $rebuildProperties = ['enable_smtp', 'restrict_robots']; $success = true; if ($result->countActivities() && !$noWait) { $success = ActivityUtil::waitMultiple($result->getActivities(), $this->stdErr); } elseif (!$result->countActivities() && in_array($property, $rebuildProperties)) { $this->rebuildWarning(); } return $success ? 0 : 1; }
/** * @param string $property * @param string $value * @param Environment $environment * * @return int */ protected function setProperty($property, $value, Environment $environment) { if (!$this->validateValue($property, $value)) { return 1; } $type = $this->getType($property); if ($type === 'boolean' && $value === 'false') { $value = false; } settype($value, $type); $currentValue = $environment->getProperty($property, false); if ($currentValue === $value) { $this->stdErr->writeln("Property <info>{$property}</info> already set as: " . $environment->getProperty($property, false)); return 0; } $environment->update(array($property => $value)); $this->stdErr->writeln("Property <info>{$property}</info> set to: " . $environment[$property]); if ($property === 'enable_smtp' && !$environment->getLastActivity()) { $this->rebuildWarning(); } return 0; }
/** * Check whether a branch exists, locally in Git or on the remote. * * @param string $branch * @param Project $project * @param GitHelper $gitHelper * * @return string|false */ protected function branchExists($branch, Project $project, GitHelper $gitHelper) { // Check if the Git branch exists locally. $candidates = array_unique(array(Environment::sanitizeId($branch), $branch)); foreach ($candidates as $candidate) { if ($gitHelper->branchExists($candidate)) { return $candidate; } } // Check if the environment exists by title or ID. This is usually faster // than running 'git ls-remote'. $environments = $this->getEnvironments($project); foreach ($environments as $environment) { if ($environment['title'] == $branch || $environment['id'] == $branch) { return $environment['id']; } } return false; }
/** * Get the current environment if the user is in a project directory. * * @param Project $expectedProject The expected project. * * @return Environment|false The current environment. */ public function getCurrentEnvironment(Project $expectedProject = null) { if (!($projectRoot = $this->getProjectRoot()) || !($project = $this->getCurrentProject()) || $expectedProject !== null && $expectedProject->id !== $project->id) { return false; } $gitHelper = $this->getHelper('git'); $gitHelper->setDefaultRepositoryDir($this->getProjectRoot() . '/' . LocalProject::REPOSITORY_DIR); $currentBranch = $gitHelper->getCurrentBranch(); // Check if there is a manual mapping set for the current branch. if ($currentBranch) { $config = $this->getProjectConfig($projectRoot); if (!empty($config['mapping'][$currentBranch])) { $environment = $this->getEnvironment($config['mapping'][$currentBranch], $project); if ($environment) { $this->debug('Found mapped environment for branch ' . $currentBranch . ': ' . $environment->id); return $environment; } else { unset($config['mapping'][$currentBranch]); $this->setProjectConfig('mapping', $config['mapping'], $projectRoot); } } } // Check whether the user has a Git upstream set to a Platform // environment ID. $upstream = $gitHelper->getUpstream(); if ($upstream && strpos($upstream, '/') !== false) { list(, $potentialEnvironment) = explode('/', $upstream, 2); $environment = $this->getEnvironment($potentialEnvironment, $project); if ($environment) { $this->debug('Selected environment ' . $potentialEnvironment . ', based on Git upstream: ' . $upstream); return $environment; } } // There is no Git remote set, or it's set to a non-Platform URL. // Fall back to trying the current branch name. if ($currentBranch) { $currentBranchSanitized = Environment::sanitizeId($currentBranch); $environment = $this->getEnvironment($currentBranchSanitized, $project); if ($environment) { $this->debug('Selected environment ' . $currentBranchSanitized . ', based on branch name:' . $currentBranch); return $environment; } } return false; }
protected function execute(InputInterface $input, OutputInterface $output) { $this->envArgName = 'parent'; $this->validateInput($input, true); $selectedProject = $this->getSelectedProject(); $branchName = $input->getArgument('name'); if (empty($branchName)) { if ($input->isInteractive()) { // List environments. return $this->runOtherCommand('environments', array('--project' => $selectedProject->id)); } $this->stdErr->writeln("<error>You must specify the name of the new branch.</error>"); return 1; } $machineName = Environment::sanitizeId($branchName); $environmentId = $this->getSelectedEnvironment()['id']; if ($machineName == $environmentId) { $this->stdErr->writeln("<comment>Already on {$machineName}</comment>"); return 1; } if ($environment = $this->getEnvironment($machineName, $selectedProject)) { $checkout = $this->getHelper('question')->confirm("The environment <comment>{$machineName}</comment> already exists. Check out?", $input, $this->stdErr); if ($checkout) { return $this->runOtherCommand('environment:checkout', array('id' => $environment->id)); } return 1; } if (!$this->getSelectedEnvironment()->operationAvailable('branch')) { $this->stdErr->writeln("Operation not available: The environment <error>{$environmentId}</error> can't be branched."); return 1; } $force = $input->getOption('force'); $projectRoot = $this->getProjectRoot(); if (!$projectRoot && $force) { $this->stdErr->writeln("<comment>This command was run from outside your local project root, the new Platform.sh branch cannot be checked out in your local Git repository." . " Make sure to run 'platform checkout' or 'git checkout' in your repository directory to switch to the branch you are expecting.</comment>"); $local_error = true; } elseif (!$projectRoot) { $this->stdErr->writeln("<error>You must run this command inside the project root, or specify --force.</error>"); return 1; } $selectedEnvironment = $this->getSelectedEnvironment(); $this->stdErr->writeln("Creating a new environment <info>{$branchName}</info>, branched from <info>{$selectedEnvironment['title']}</info>"); $activity = $selectedEnvironment->branch($branchName, $machineName); // Clear the environments cache, as branching has started. $this->clearEnvironmentsCache($selectedProject); if ($projectRoot) { $gitHelper = new GitHelper(new ShellHelper($this->stdErr)); $gitHelper->setDefaultRepositoryDir($projectRoot . '/' . LocalProject::REPOSITORY_DIR); // If the Git branch already exists locally, just check it out. $existsLocally = $gitHelper->branchExists($machineName); if ($existsLocally) { $this->stdErr->writeln("Checking out <info>{$machineName}</info> locally"); if (!$gitHelper->checkOut($machineName)) { $this->stdErr->writeln('<error>Failed to check out branch locally: ' . $machineName . '</error>'); $local_error = true; if (!$force) { return 1; } } } else { // Create a new branch, using the current or specified environment as the parent if it exists locally. $parent = $this->getSelectedEnvironment()['id']; if (!$gitHelper->branchExists($parent)) { $parent = null; } $this->stdErr->writeln("Creating local branch <info>{$machineName}</info>"); if (!$gitHelper->checkOutNew($machineName, $parent)) { $this->stdErr->writeln('<error>Failed to create branch locally: ' . $machineName . '</error>'); $local_error = true; if (!$force) { return 1; } } } } $remoteSuccess = true; if (!$input->getOption('no-wait')) { $remoteSuccess = ActivityUtil::waitAndLog($activity, $this->stdErr, "The environment <info>{$branchName}</info> has been branched.", '<error>Branching failed</error>'); // Clear the environments cache again. $this->clearEnvironmentsCache($selectedProject); } $build = $input->getOption('build'); if (empty($local_error) && $build && $projectRoot) { // Build the new branch. try { $buildSettings = array('environmentId' => $machineName, 'verbosity' => $output->getVerbosity()); $builder = new LocalBuild($buildSettings, $output); $builder->buildProject($projectRoot); } catch (\Exception $e) { $this->stdErr->writeln("<comment>The new branch could not be built: \n" . $e->getMessage() . "</comment>"); return 1; } } $this->clearEnvironmentsCache(); return $remoteSuccess ? 0 : 1; }
/** * Return the user's environments. * * @param Project $project The project. * @param bool $refresh Whether to refresh the list. * @param bool $updateAliases Whether to update Drush aliases if the list changes. * * @return Environment[] The user's environments. */ public function getEnvironments(Project $project = null, $refresh = false, $updateAliases = true) { $project = $project ?: $this->getSelectedProject(); $projectId = $project->getProperty('id'); $this->loadCache(); $cached = !empty(self::$cache['environments'][$projectId]); $stale = isset(self::$cache['environmentsRefreshed'][$projectId]) && time() - self::$cache['environmentsRefreshed'][$projectId] > $this->environmentsTtl; if ($refresh || !$cached || $stale) { self::$cache['environments'][$projectId] = array(); $environments = array(); $toCache = array(); foreach ($project->getEnvironments() as $environment) { $environments[$environment['id']] = $environment; $toCache[$environment['id']] = $environment->getData(); } // Recreate the aliases if the list of environments has changed. if ($updateAliases && array_diff_key($environments, self::$cache['environments'])) { $this->updateDrushAliases($project, $environments); } self::$cache['environments'][$projectId] = $toCache; self::$cache['environmentsRefreshed'][$projectId] = time(); } else { $environments = array(); $connector = $this->getClient(false)->getConnector(); $endpoint = $project->hasLink('self') ? $project->getLink('self', true) : $project['endpoint']; $client = $connector->getClient(); foreach (self::$cache['environments'][$projectId] as $id => $data) { $environments[$id] = Environment::wrap($data, $endpoint, $client); } } return $environments; }
/** * Return the user's environments. * * @param Project $project The project. * @param bool $refresh Whether to refresh the list. * @param bool $updateAliases Whether to update Drush aliases if the list changes. * * @return Environment[] The user's environments. */ public function getEnvironments(Project $project = null, $refresh = false, $updateAliases = true) { $project = $project ?: $this->getSelectedProject(); $projectId = $project->getProperty('id'); $cacheKey = 'environments:' . $projectId; $cached = self::$cache->contains($cacheKey); if ($refresh || !$cached) { $environments = array(); $toCache = array(); foreach ($project->getEnvironments() as $environment) { $environments[$environment['id']] = $environment; $toCache[$environment['id']] = $environment->getData(); } // Recreate the aliases if the list of environments has changed. if ($updateAliases && (!$cached || array_diff_key($environments, self::$cache->fetch($cacheKey)))) { $this->updateDrushAliases($project, $environments); } self::$cache->save($cacheKey, $toCache, $this->environmentsTtl); } else { $environments = array(); $connector = $this->getClient(false)->getConnector(); $endpoint = $project->hasLink('self') ? $project->getLink('self', true) : $project['endpoint']; $client = $connector->getClient(); foreach ((array) self::$cache->fetch($cacheKey) as $id => $data) { $environments[$id] = Environment::wrap($data, $endpoint, $client); } } return $environments; }
/** * Get the current environment if the user is in a project directory. * * @param Project $expectedProject The expected project. * @param bool|null $refresh Whether to refresh the environments or projects * cache. * * @return Environment|false The current environment. */ public function getCurrentEnvironment(Project $expectedProject = null, $refresh = null) { if (!($projectRoot = $this->getProjectRoot()) || !($project = $this->getCurrentProject()) || $expectedProject !== null && $expectedProject->id !== $project->id) { return false; } $gitHelper = $this->getHelper('git'); $gitHelper->setDefaultRepositoryDir($this->getProjectRoot()); $config = $this->localProject->getProjectConfig($projectRoot); // Check if there is a manual mapping set for the current branch. if (!empty($config['mapping']) && ($currentBranch = $gitHelper->getCurrentBranch()) && !empty($config['mapping'][$currentBranch])) { $environment = $this->api()->getEnvironment($config['mapping'][$currentBranch], $project, $refresh); if ($environment) { $this->debug('Found mapped environment for branch ' . $currentBranch . ': ' . $environment->id); return $environment; } else { unset($config['mapping'][$currentBranch]); $this->localProject->writeCurrentProjectConfig($config, $projectRoot); } } // Check whether the user has a Git upstream set to a remote environment // ID. $upstream = $gitHelper->getUpstream(); if ($upstream && strpos($upstream, '/') !== false) { list(, $potentialEnvironment) = explode('/', $upstream, 2); $environment = $this->api()->getEnvironment($potentialEnvironment, $project, $refresh); if ($environment) { $this->debug('Selected environment ' . $potentialEnvironment . ', based on Git upstream: ' . $upstream); return $environment; } } // There is no Git remote set. Fall back to trying the current branch // name. if (!empty($currentBranch) || ($currentBranch = $gitHelper->getCurrentBranch())) { $environment = $this->api()->getEnvironment($currentBranch, $project, $refresh); if (!$environment) { // Try a sanitized version of the branch name too. $currentBranchSanitized = Environment::sanitizeId($currentBranch); $environment = $this->api()->getEnvironment($currentBranchSanitized, $project, $refresh); } if ($environment) { $this->debug('Selected environment ' . $environment->id . ' based on branch name: ' . $currentBranch); return $environment; } } return false; }
/** * @param Environment $environment * * @return array|false */ protected function generateRemoteAlias($environment) { if (!$environment->hasLink('ssh')) { return false; } $sshUrl = parse_url($environment->getLink('ssh')); if (!$sshUrl) { return false; } return array('uri' => $environment->getLink('public-url'), 'remote-host' => $sshUrl['host'], 'remote-user' => $sshUrl['user'], 'root' => '/app/public', self::AUTO_REMOVE_KEY => true); }
/** * @param Environment $environment * @param LocalApplication $app * @param bool $multiApp * * @return array|false */ protected function generateRemoteAlias($environment, $app, $multiApp = false) { if (!$environment->hasLink('ssh') || !$environment->hasLink('public-url')) { return false; } $sshUrl = parse_url($environment->getLink('ssh')); if (!$sshUrl) { return false; } $sshUser = $sshUrl['user']; if ($multiApp) { $sshUser .= '--' . $app->getName(); } $uri = $environment->getLink('public-url'); if ($multiApp) { $guess = str_replace('http://', 'http://' . $app->getName() . '---', $uri); if (in_array($guess, $environment->getRouteUrls())) { $uri = $guess; } } $appConfig = $app->getConfig(); $documentRoot = '/public'; if (isset($appConfig['web']['document_root']) && $appConfig['web']['document_root'] !== '/') { $documentRoot = $appConfig['web']['document_root']; } return ['uri' => $uri, 'remote-host' => $sshUrl['host'], 'remote-user' => $sshUser, 'root' => '/app/' . ltrim($documentRoot, '/'), self::AUTO_REMOVE_KEY => true, 'command-specific' => ['site-install' => ['sites-subdir' => 'default']]]; }
/** * @param Environment $environment * * @return array|false */ protected function generateRemoteAlias($environment) { if (!$environment->hasLink('ssh')) { return false; } $sshUrl = parse_url($environment->getLink('ssh')); if (!$sshUrl) { return false; } return array('uri' => $environment->getLink('public-url'), 'remote-host' => $sshUrl['host'], 'remote-user' => $sshUrl['user'], 'root' => '/app/public', self::AUTO_REMOVE_KEY => true, 'command-specific' => array('site-install' => array('sites-subdir' => 'default'))); }
/** * @param Environment $environment * @param LocalApplication $app * @param bool $multiApp * * @return array|false */ protected function generateRemoteAlias($environment, $app, $multiApp = false) { if (!$environment->hasLink('ssh') || !$environment->hasLink('public-url')) { return false; } $sshUrl = parse_url($environment->getLink('ssh')); if (!$sshUrl) { return false; } $sshUser = $sshUrl['user']; if ($multiApp) { $sshUser .= '--' . $app->getName(); } $uri = $environment->getLink('public-url'); if ($multiApp) { $guess = str_replace('http://', 'http://' . $app->getName() . '---', $uri); if (in_array($guess, $environment->getRouteUrls())) { $uri = $guess; } } return ['uri' => $uri, 'remote-host' => $sshUrl['host'], 'remote-user' => $sshUser, 'root' => '/app/' . $app->getDocumentRoot(), $this->getAutoRemoveKey() => true, 'command-specific' => ['site-install' => ['sites-subdir' => 'default']]]; }