JsonConfigSource.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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\Config;
  12. use Composer\Json\JsonFile;
  13. use Composer\Json\JsonManipulator;
  14. use Composer\Util\Silencer;
  15. /**
  16. * JSON Configuration Source
  17. *
  18. * @author Jordi Boggiano <j.boggiano@seld.be>
  19. * @author Beau Simensen <beau@dflydev.com>
  20. */
  21. class JsonConfigSource implements ConfigSourceInterface
  22. {
  23. /**
  24. * @var JsonFile
  25. */
  26. private $file;
  27. /**
  28. * @var bool
  29. */
  30. private $authConfig;
  31. /**
  32. * Constructor
  33. *
  34. * @param JsonFile $file
  35. * @param bool $authConfig
  36. */
  37. public function __construct(JsonFile $file, $authConfig = false)
  38. {
  39. $this->file = $file;
  40. $this->authConfig = $authConfig;
  41. }
  42. /**
  43. * {@inheritdoc}
  44. */
  45. public function getName()
  46. {
  47. return $this->file->getPath();
  48. }
  49. /**
  50. * {@inheritdoc}
  51. */
  52. public function addRepository($name, $config)
  53. {
  54. $this->manipulateJson('addRepository', $name, $config, function (&$config, $repo, $repoConfig) {
  55. $config['repositories'][$repo] = $repoConfig;
  56. });
  57. }
  58. /**
  59. * {@inheritdoc}
  60. */
  61. public function removeRepository($name)
  62. {
  63. $this->manipulateJson('removeRepository', $name, function (&$config, $repo) {
  64. unset($config['repositories'][$repo]);
  65. });
  66. }
  67. /**
  68. * {@inheritdoc}
  69. */
  70. public function addConfigSetting($name, $value)
  71. {
  72. $authConfig = $this->authConfig;
  73. $this->manipulateJson('addConfigSetting', $name, $value, function (&$config, $key, $val) use ($authConfig) {
  74. if (preg_match('{^(github-oauth|gitlab-oauth|http-basic|platform|bitbucket)\.}', $key)) {
  75. list($key, $host) = explode('.', $key, 2);
  76. if ($authConfig) {
  77. $config[$key][$host] = $val;
  78. } else {
  79. $config['config'][$key][$host] = $val;
  80. }
  81. } else {
  82. $config['config'][$key] = $val;
  83. }
  84. });
  85. }
  86. /**
  87. * {@inheritdoc}
  88. */
  89. public function removeConfigSetting($name)
  90. {
  91. $authConfig = $this->authConfig;
  92. $this->manipulateJson('removeConfigSetting', $name, function (&$config, $key) use ($authConfig) {
  93. if (preg_match('{^(github-oauth|gitlab-oauth|http-basic|platform)\.}', $key)) {
  94. list($key, $host) = explode('.', $key, 2);
  95. if ($authConfig) {
  96. unset($config[$key][$host]);
  97. } else {
  98. unset($config['config'][$key][$host]);
  99. }
  100. } else {
  101. unset($config['config'][$key]);
  102. }
  103. });
  104. }
  105. /**
  106. * {@inheritdoc}
  107. */
  108. public function addLink($type, $name, $value)
  109. {
  110. $this->manipulateJson('addLink', $type, $name, $value, function (&$config, $type, $name, $value) {
  111. $config[$type][$name] = $value;
  112. });
  113. }
  114. /**
  115. * {@inheritdoc}
  116. */
  117. public function removeLink($type, $name)
  118. {
  119. $this->manipulateJson('removeSubNode', $type, $name, function (&$config, $type, $name) {
  120. unset($config[$type][$name]);
  121. });
  122. }
  123. protected function manipulateJson($method, $args, $fallback)
  124. {
  125. $args = func_get_args();
  126. // remove method & fallback
  127. array_shift($args);
  128. $fallback = array_pop($args);
  129. if ($this->file->exists()) {
  130. if (!is_writable($this->file->getPath())) {
  131. throw new \RuntimeException(sprintf('The file "%s" is not writable.', $this->file->getPath()));
  132. }
  133. if (!is_readable($this->file->getPath())) {
  134. throw new \RuntimeException(sprintf('The file "%s" is not readable.', $this->file->getPath()));
  135. }
  136. $contents = file_get_contents($this->file->getPath());
  137. } elseif ($this->authConfig) {
  138. $contents = "{\n}\n";
  139. } else {
  140. $contents = "{\n \"config\": {\n }\n}\n";
  141. }
  142. $manipulator = new JsonManipulator($contents);
  143. $newFile = !$this->file->exists();
  144. // override manipulator method for auth config files
  145. if ($this->authConfig && $method === 'addConfigSetting') {
  146. $method = 'addSubNode';
  147. list($mainNode, $name) = explode('.', $args[0], 2);
  148. $args = array($mainNode, $name, $args[1]);
  149. } elseif ($this->authConfig && $method === 'removeConfigSetting') {
  150. $method = 'removeSubNode';
  151. list($mainNode, $name) = explode('.', $args[0], 2);
  152. $args = array($mainNode, $name);
  153. }
  154. // try to update cleanly
  155. if (call_user_func_array(array($manipulator, $method), $args)) {
  156. file_put_contents($this->file->getPath(), $manipulator->getContents());
  157. } else {
  158. // on failed clean update, call the fallback and rewrite the whole file
  159. $config = $this->file->read();
  160. $this->arrayUnshiftRef($args, $config);
  161. call_user_func_array($fallback, $args);
  162. $this->file->write($config);
  163. }
  164. if ($newFile) {
  165. Silencer::call('chmod', $this->file->getPath(), 0600);
  166. }
  167. }
  168. /**
  169. * Prepend a reference to an element to the beginning of an array.
  170. *
  171. * @param array $array
  172. * @param mixed $value
  173. * @return array
  174. */
  175. private function arrayUnshiftRef(&$array, &$value)
  176. {
  177. $return = array_unshift($array, '');
  178. $array[0] = &$value;
  179. return $return;
  180. }
  181. }