SvnDriver.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. <?php
  2. namespace Composer\Repository\Vcs;
  3. use Composer\Json\JsonFile;
  4. /**
  5. * @author Jordi Boggiano <j.boggiano@seld.be>
  6. */
  7. class SvnDriver implements VcsDriverInterface
  8. {
  9. protected $url;
  10. protected $baseUrl;
  11. protected $tags;
  12. protected $branches;
  13. protected $infoCache = array();
  14. public function __construct($url)
  15. {
  16. $this->url = $this->baseUrl = rtrim($url, '/');
  17. if (false !== ($pos = strrpos($url, '/trunk'))) {
  18. $this->baseUrl = substr($url, 0, $pos);
  19. }
  20. }
  21. /**
  22. * {@inheritDoc}
  23. */
  24. public function initialize()
  25. {
  26. $this->getBranches();
  27. $this->getTags();
  28. }
  29. /**
  30. * {@inheritDoc}
  31. */
  32. public function getRootIdentifier()
  33. {
  34. return 'trunk';
  35. }
  36. /**
  37. * {@inheritDoc}
  38. */
  39. public function getUrl()
  40. {
  41. return $this->url;
  42. }
  43. /**
  44. * {@inheritDoc}
  45. */
  46. public function getSource($identifier)
  47. {
  48. return array('type' => 'svn', 'url' => $this->baseUrl, 'reference' => $identifier);
  49. }
  50. /**
  51. * {@inheritDoc}
  52. */
  53. public function getDist($identifier)
  54. {
  55. return null;
  56. }
  57. /**
  58. * {@inheritDoc}
  59. */
  60. public function getComposerInformation($identifier)
  61. {
  62. if (!isset($this->infoCache[$identifier])) {
  63. preg_match('{^(.+?)(@\d+)?$}', $identifier, $match);
  64. if (!empty($match[2])) {
  65. $identifier = $match[1];
  66. $rev = $match[2];
  67. } else {
  68. $rev = '';
  69. }
  70. exec(sprintf('svn cat --non-interactive %s', escapeshellarg($this->baseUrl.$identifier.'composer.json'.$rev)), $output);
  71. $composer = implode("\n", $output);
  72. unset($output);
  73. if (!$composer) {
  74. throw new \UnexpectedValueException('Failed to retrieve composer information for identifier '.$identifier.' in '.$this->getUrl());
  75. }
  76. $composer = JsonFile::parseJson($composer);
  77. if (!isset($composer['time'])) {
  78. exec(sprintf('svn info %s', escapeshellarg($this->baseUrl.$identifier.$rev)), $output);
  79. foreach ($output as $line) {
  80. if (preg_match('{^Last Changed Date: ([^(]+)}', $line, $match)) {
  81. $date = new \DateTime($match[1]);
  82. $composer['time'] = $date->format('Y-m-d H:i:s');
  83. break;
  84. }
  85. }
  86. }
  87. $this->infoCache[$identifier] = $composer;
  88. }
  89. return $this->infoCache[$identifier];
  90. }
  91. /**
  92. * {@inheritDoc}
  93. */
  94. public function getTags()
  95. {
  96. if (null === $this->tags) {
  97. exec(sprintf('svn ls --non-interactive %s', escapeshellarg($this->baseUrl.'/tags')), $output);
  98. $this->tags = array();
  99. foreach ($output as $tag) {
  100. $this->tags[rtrim($tag, '/')] = '/tags/'.$tag;
  101. }
  102. }
  103. return $this->tags;
  104. }
  105. /**
  106. * {@inheritDoc}
  107. */
  108. public function getBranches()
  109. {
  110. if (null === $this->branches) {
  111. exec(sprintf('svn ls --verbose --non-interactive %s', escapeshellarg($this->baseUrl.'/')), $output);
  112. $this->branches = array();
  113. foreach ($output as $line) {
  114. preg_match('{^\s*(\S+).*?(\S+)\s*$}', $line, $match);
  115. if ($match[2] === 'trunk/') {
  116. $this->branches['trunk'] = '/trunk/@'.$match[1];
  117. break;
  118. }
  119. }
  120. unset($output);
  121. exec(sprintf('svn ls --verbose --non-interactive %s', escapeshellarg($this->baseUrl.'/branches')), $output);
  122. foreach ($output as $line) {
  123. preg_match('{^\s*(\S+).*?(\S+)\s*$}', $line, $match);
  124. if ($match[2] === './') {
  125. continue;
  126. }
  127. $this->branches[rtrim($match[2], '/')] = '/branches/'.$match[2].'@'.$match[1];
  128. }
  129. }
  130. return $this->branches;
  131. }
  132. /**
  133. * {@inheritDoc}
  134. */
  135. public function hasComposerFile($identifier)
  136. {
  137. try {
  138. $this->getComposerInformation($identifier);
  139. return true;
  140. } catch (\Exception $e) {
  141. }
  142. return false;
  143. }
  144. /**
  145. * {@inheritDoc}
  146. */
  147. public static function supports($url, $deep = false)
  148. {
  149. if (preg_match('#(^svn://|//svn\.)#i', $url)) {
  150. return true;
  151. }
  152. if (!$deep) {
  153. return false;
  154. }
  155. exec(sprintf('svn info --non-interactive %s', escapeshellarg($url)), $output);
  156. return preg_match('{^Repository UUID:}m', implode("\n", $output)) >= 1;
  157. }
  158. }