Hg.php 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. <?php
  2. /*
  3. * This file is part of Composer.
  4. *
  5. * (c) Nils Adermann <naderman@naderman.de>
  6. * Jordi Boggiano <j.boggiano@seld.be>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. namespace Composer\Util;
  12. use Composer\Config;
  13. use Composer\IO\IOInterface;
  14. /**
  15. * @author Jonas Renaudot <jonas.renaudot@gmail.com>
  16. */
  17. class Hg
  18. {
  19. /**
  20. * @var \Composer\IO\IOInterface
  21. */
  22. private $io;
  23. /**
  24. * @var \Composer\Config
  25. */
  26. private $config;
  27. /**
  28. * @var \Composer\Util\ProcessExecutor
  29. */
  30. private $process;
  31. public function __construct(IOInterface $io, Config $config, ProcessExecutor $process)
  32. {
  33. $this->io = $io;
  34. $this->config = $config;
  35. $this->process = $process;
  36. }
  37. public function runCommand($commandCallable, $url, $cwd)
  38. {
  39. $this->config->prohibitUrlByConfig($url, $this->io);
  40. // Try as is
  41. $command = call_user_func($commandCallable, $url);
  42. if (0 === $this->process->execute($command, $ignoredOutput, $cwd)) {
  43. return;
  44. }
  45. // Try with the authentication informations available
  46. if (preg_match('{^(https?)://((.+)(?:\:(.+))?@)?([^/]+)(/.*)?}mi', $url, $match) && $this->io->hasAuthentication($match[5])) {
  47. $auth = $this->io->getAuthentication($match[5]);
  48. $authenticatedUrl = $match[1] . '://' . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $match[5] . (!empty($match[6]) ? $match[6] : null);
  49. $command = call_user_func($commandCallable, $authenticatedUrl);
  50. if (0 === $this->process->execute($command)) {
  51. return;
  52. }
  53. $error = $this->process->getErrorOutput();
  54. } else {
  55. $error = 'The given URL (' . $url . ') does not match the required format (http(s)://(username:password@)example.com/path-to-repository)';
  56. }
  57. $this->throwException('Failed to clone ' . $url . ', ' . "\n\n" . $error, $url);
  58. }
  59. public static function sanitizeUrl($message)
  60. {
  61. return preg_replace_callback('{://(?P<user>[^@]+?):(?P<password>.+?)@}', function ($m) {
  62. if (preg_match('{^[a-f0-9]{12,}$}', $m[1])) {
  63. return '://***:***@';
  64. }
  65. return '://' . $m[1] . ':***@';
  66. }, $message);
  67. }
  68. private function throwException($message, $url)
  69. {
  70. if (0 !== $this->process->execute('hg --version', $ignoredOutput)) {
  71. throw new \RuntimeException(self::sanitizeUrl('Failed to clone ' . $url . ', hg was not found, check that it is installed and in your PATH env.' . "\n\n" . $this->process->getErrorOutput()));
  72. }
  73. throw new \RuntimeException(self::sanitizeUrl($message));
  74. }
  75. }