/** * {@inheritDoc} */ protected function execute(InputInterface $input, OutputInterface $output) { // Open file in editor if ($input->getOption('editor')) { $editor = escapeshellcmd(getenv('EDITOR')); if (!$editor) { if (Platform::isWindows()) { $editor = 'notepad'; } else { foreach (array('editor', 'vim', 'vi', 'nano', 'pico', 'ed') as $candidate) { if (exec('which ' . $candidate)) { $editor = $candidate; break; } } } } $file = $input->getOption('auth') ? $this->authConfigFile->getPath() : $this->configFile->getPath(); system($editor . ' ' . $file . (Platform::isWindows() ? '' : ' > `tty`')); return 0; } if (!$input->getOption('global')) { $this->config->merge($this->configFile->read()); $this->config->merge(array('config' => $this->authConfigFile->exists() ? $this->authConfigFile->read() : array())); } // List the configuration of the file settings if ($input->getOption('list')) { $this->listConfiguration($this->config->all(), $this->config->raw(), $output); return 0; } $settingKey = $input->getArgument('setting-key'); if (!$settingKey) { return 0; } // If the user enters in a config variable, parse it and save to file if (array() !== $input->getArgument('setting-value') && $input->getOption('unset')) { throw new \RuntimeException('You can not combine a setting value with --unset'); } // show the value if no value is provided if (array() === $input->getArgument('setting-value') && !$input->getOption('unset')) { $properties = array('name', 'type', 'description', 'homepage', 'version', 'minimum-stability', 'prefer-stable', 'keywords', 'license', 'extra'); $rawData = $this->configFile->read(); $data = $this->config->all(); if (preg_match('/^repos?(?:itories)?(?:\\.(.+))?/', $settingKey, $matches)) { if (!isset($matches[1]) || $matches[1] === '') { $value = isset($data['repositories']) ? $data['repositories'] : array(); } else { if (!isset($data['repositories'][$matches[1]])) { throw new \InvalidArgumentException('There is no ' . $matches[1] . ' repository defined'); } $value = $data['repositories'][$matches[1]]; } } elseif (strpos($settingKey, '.')) { $bits = explode('.', $settingKey); if ($bits[0] === 'extra') { $data = $rawData; } else { $data = $data['config']; } $match = false; foreach ($bits as $bit) { $key = isset($key) ? $key . '.' . $bit : $bit; $match = false; if (isset($data[$key])) { $match = true; $data = $data[$key]; unset($key); } } if (!$match) { throw new \RuntimeException($settingKey . ' is not defined.'); } $value = $data; } elseif (isset($data['config'][$settingKey])) { $value = $this->config->get($settingKey, $input->getOption('absolute') ? 0 : Config::RELATIVE_PATHS); } elseif (in_array($settingKey, $properties, true) && isset($rawData[$settingKey])) { $value = $rawData[$settingKey]; } else { throw new \RuntimeException($settingKey . ' is not defined'); } if (is_array($value)) { $value = json_encode($value); } $this->getIO()->write($value); return 0; } $values = $input->getArgument('setting-value'); // what the user is trying to add/change $booleanValidator = function ($val) { return in_array($val, array('true', 'false', '1', '0'), true); }; $booleanNormalizer = function ($val) { return $val !== 'false' && (bool) $val; }; // handle config values $uniqueConfigValues = array('process-timeout' => array('is_numeric', 'intval'), 'use-include-path' => array($booleanValidator, $booleanNormalizer), 'preferred-install' => array(function ($val) { return in_array($val, array('auto', 'source', 'dist'), true); }, function ($val) { return $val; }), 'store-auths' => array(function ($val) { return in_array($val, array('true', 'false', 'prompt'), true); }, function ($val) { if ('prompt' === $val) { return 'prompt'; } return $val !== 'false' && (bool) $val; }), 'notify-on-install' => array($booleanValidator, $booleanNormalizer), 'vendor-dir' => array('is_string', function ($val) { return $val; }), 'bin-dir' => array('is_string', function ($val) { return $val; }), 'archive-dir' => array('is_string', function ($val) { return $val; }), 'archive-format' => array('is_string', function ($val) { return $val; }), 'data-dir' => array('is_string', function ($val) { return $val; }), 'cache-dir' => array('is_string', function ($val) { return $val; }), 'cache-files-dir' => array('is_string', function ($val) { return $val; }), 'cache-repo-dir' => array('is_string', function ($val) { return $val; }), 'cache-vcs-dir' => array('is_string', function ($val) { return $val; }), 'cache-ttl' => array('is_numeric', 'intval'), 'cache-files-ttl' => array('is_numeric', 'intval'), 'cache-files-maxsize' => array(function ($val) { return preg_match('/^\\s*([0-9.]+)\\s*(?:([kmg])(?:i?b)?)?\\s*$/i', $val) > 0; }, function ($val) { return $val; }), 'bin-compat' => array(function ($val) { return in_array($val, array('auto', 'full')); }, function ($val) { return $val; }), 'discard-changes' => array(function ($val) { return in_array($val, array('stash', 'true', 'false', '1', '0'), true); }, function ($val) { if ('stash' === $val) { return 'stash'; } return $val !== 'false' && (bool) $val; }), 'autoloader-suffix' => array('is_string', function ($val) { return $val === 'null' ? null : $val; }), 'sort-packages' => array($booleanValidator, $booleanNormalizer), 'optimize-autoloader' => array($booleanValidator, $booleanNormalizer), 'classmap-authoritative' => array($booleanValidator, $booleanNormalizer), 'prepend-autoloader' => array($booleanValidator, $booleanNormalizer), 'disable-tls' => array($booleanValidator, $booleanNormalizer), 'secure-http' => array($booleanValidator, $booleanNormalizer), 'cafile' => array(function ($val) { return file_exists($val) && is_readable($val); }, function ($val) { return $val === 'null' ? null : $val; }), 'capath' => array(function ($val) { return is_dir($val) && is_readable($val); }, function ($val) { return $val === 'null' ? null : $val; }), 'github-expose-hostname' => array($booleanValidator, $booleanNormalizer)); $multiConfigValues = array('github-protocols' => array(function ($vals) { if (!is_array($vals)) { return 'array expected'; } foreach ($vals as $val) { if (!in_array($val, array('git', 'https', 'ssh'))) { return 'valid protocols include: git, https, ssh'; } } return true; }, function ($vals) { return $vals; }), 'github-domains' => array(function ($vals) { if (!is_array($vals)) { return 'array expected'; } return true; }, function ($vals) { return $vals; }), 'gitlab-domains' => array(function ($vals) { if (!is_array($vals)) { return 'array expected'; } return true; }, function ($vals) { return $vals; })); if ($input->getOption('unset') && (isset($uniqueConfigValues[$settingKey]) || isset($multiConfigValues[$settingKey]))) { return $this->configSource->removeConfigSetting($settingKey); } if (isset($uniqueConfigValues[$settingKey])) { return $this->handleSingleValue($settingKey, $uniqueConfigValues[$settingKey], $values, 'addConfigSetting'); } if (isset($multiConfigValues[$settingKey])) { return $this->handleMultiValue($settingKey, $multiConfigValues[$settingKey], $values, 'addConfigSetting'); } // handle properties $uniqueProps = array('name' => array('is_string', function ($val) { return $val; }), 'type' => array('is_string', function ($val) { return $val; }), 'description' => array('is_string', function ($val) { return $val; }), 'homepage' => array('is_string', function ($val) { return $val; }), 'version' => array('is_string', function ($val) { return $val; }), 'minimum-stability' => array(function ($val) { return isset(BasePackage::$stabilities[VersionParser::normalizeStability($val)]); }, function ($val) { return VersionParser::normalizeStability($val); }), 'prefer-stable' => array($booleanValidator, $booleanNormalizer)); $multiProps = array('keywords' => array(function ($vals) { if (!is_array($vals)) { return 'array expected'; } return true; }, function ($vals) { return $vals; }), 'license' => array(function ($vals) { if (!is_array($vals)) { return 'array expected'; } return true; }, function ($vals) { return $vals; })); if ($input->getOption('global') && (isset($uniqueProps[$settingKey]) || isset($multiProps[$settingKey]) || substr($settingKey, 0, 6) === 'extra.')) { throw new \InvalidArgumentException('The ' . $settingKey . ' property can not be set in the global config.json file. Use `composer global config` to apply changes to the global composer.json'); } if ($input->getOption('unset') && (isset($uniqueProps[$settingKey]) || isset($multiProps[$settingKey]))) { return $this->configSource->removeProperty($settingKey); } if (isset($uniqueProps[$settingKey])) { return $this->handleSingleValue($settingKey, $uniqueProps[$settingKey], $values, 'addProperty'); } if (isset($multiProps[$settingKey])) { return $this->handleMultiValue($settingKey, $multiProps[$settingKey], $values, 'addProperty'); } // handle repositories if (preg_match('/^repos?(?:itories)?\\.(.+)/', $settingKey, $matches)) { if ($input->getOption('unset')) { return $this->configSource->removeRepository($matches[1]); } if (2 === count($values)) { return $this->configSource->addRepository($matches[1], array('type' => $values[0], 'url' => $values[1])); } if (1 === count($values)) { $value = strtolower($values[0]); if (true === $booleanValidator($value)) { if (false === $booleanNormalizer($value)) { return $this->configSource->addRepository($matches[1], false); } } else { $value = JsonFile::parseJson($values[0]); return $this->configSource->addRepository($matches[1], $value); } } throw new \RuntimeException('You must pass the type and a url. Example: php composer.phar config repositories.foo vcs https://bar.com'); } // handle extra if (preg_match('/^extra\\.(.+)/', $settingKey, $matches)) { if ($input->getOption('unset')) { return $this->configSource->removeProperty($settingKey); } return $this->configSource->addProperty($settingKey, $values[0]); } // handle platform if (preg_match('/^platform\\.(.+)/', $settingKey, $matches)) { if ($input->getOption('unset')) { return $this->configSource->removeConfigSetting($settingKey); } return $this->configSource->addConfigSetting($settingKey, $values[0]); } // handle auth if (preg_match('/^(bitbucket-oauth|github-oauth|gitlab-oauth|gitlab-token|http-basic)\\.(.+)/', $settingKey, $matches)) { if ($input->getOption('unset')) { $this->authConfigSource->removeConfigSetting($matches[1] . '.' . $matches[2]); $this->configSource->removeConfigSetting($matches[1] . '.' . $matches[2]); return; } if ($matches[1] === 'bitbucket-oauth') { if (2 !== count($values)) { throw new \RuntimeException('Expected two arguments (consumer-key, consumer-secret), got ' . count($values)); } $this->configSource->removeConfigSetting($matches[1] . '.' . $matches[2]); $this->authConfigSource->addConfigSetting($matches[1] . '.' . $matches[2], array('consumer-key' => $values[0], 'consumer-secret' => $values[1])); } elseif (in_array($matches[1], array('github-oauth', 'gitlab-oauth', 'gitlab-token'), true)) { if (1 !== count($values)) { throw new \RuntimeException('Too many arguments, expected only one token'); } $this->configSource->removeConfigSetting($matches[1] . '.' . $matches[2]); $this->authConfigSource->addConfigSetting($matches[1] . '.' . $matches[2], $values[0]); } elseif ($matches[1] === 'http-basic') { if (2 !== count($values)) { throw new \RuntimeException('Expected two arguments (username, password), got ' . count($values)); } $this->configSource->removeConfigSetting($matches[1] . '.' . $matches[2]); $this->authConfigSource->addConfigSetting($matches[1] . '.' . $matches[2], array('username' => $values[0], 'password' => $values[1])); } return; } throw new \InvalidArgumentException('Setting ' . $settingKey . ' does not exist or is not supported by this command'); }
private function extractStabilityFlags(array $requires, array $stabilityFlags, $minimumStability) { $stabilities = BasePackage::$stabilities; $minimumStability = $stabilities[$minimumStability]; foreach ($requires as $reqName => $reqVersion) { $constraints = array(); // extract all sub-constraints in case it is an OR/AND multi-constraint $orSplit = preg_split('{\\s*\\|\\|?\\s*}', trim($reqVersion)); foreach ($orSplit as $constraint) { $andSplit = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $constraint); foreach ($andSplit as $constraint) { $constraints[] = $constraint; } } // parse explicit stability flags to the most unstable $match = false; foreach ($constraints as $constraint) { if (preg_match('{^[^@]*?@(' . implode('|', array_keys($stabilities)) . ')$}i', $constraint, $match)) { $name = strtolower($reqName); $stability = $stabilities[VersionParser::normalizeStability($match[1])]; if (isset($stabilityFlags[$name]) && $stabilityFlags[$name] > $stability) { continue; } $stabilityFlags[$name] = $stability; $match = true; } } if ($match) { continue; } // infer flags for requirements that have an explicit -dev or -beta version specified but only // for those that are more unstable than the minimumStability or existing flags $reqVersion = preg_replace('{^([^,\\s@]+) as .+$}', '$1', $reqVersion); if (preg_match('{^[^,\\s@]+$}', $reqVersion) && 'stable' !== ($stabilityName = VersionParser::parseStability($reqVersion))) { $name = strtolower($reqName); $stability = $stabilities[$stabilityName]; if (isset($stabilityFlags[$name]) && $stabilityFlags[$name] > $stability || $minimumStability > $stability) { continue; } $stabilityFlags[$name] = $stability; } } return $stabilityFlags; }
private function extractStabilityFlags(array $requires, array $stabilityFlags, $minimumStability) { $stabilities = BasePackage::$stabilities; $minimumStability = $stabilities[$minimumStability]; foreach ($requires as $reqName => $reqVersion) { // parse explicit stability flags to the most unstable if (preg_match('{^[^@]*?@(' . implode('|', array_keys($stabilities)) . ')$}i', $reqVersion, $match)) { $name = strtolower($reqName); $stability = $stabilities[VersionParser::normalizeStability($match[1])]; if (isset($stabilityFlags[$name]) && $stabilityFlags[$name] > $stability) { continue; } $stabilityFlags[$name] = $stability; continue; } // infer flags for requirements that have an explicit -dev or -beta version specified but only // for those that are more unstable than the minimumStability or existing flags $reqVersion = preg_replace('{^([^,\\s@]+) as .+$}', '$1', $reqVersion); if (preg_match('{^[^,\\s@]+$}', $reqVersion) && 'stable' !== ($stabilityName = VersionParser::parseStability($reqVersion))) { $name = strtolower($reqName); $stability = $stabilities[$stabilityName]; if (isset($stabilityFlags[$name]) && $stabilityFlags[$name] > $stability || $minimumStability > $stability) { continue; } $stabilityFlags[$name] = $stability; } } return $stabilityFlags; }