PageRenderTime 51ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/src/PhpBrew/Variants.php

http://github.com/c9s/phpbrew
PHP | 499 lines | 353 code | 87 blank | 59 comment | 43 complexity | 10bbdfa159856e11a43bb8eb80533908 MD5 | raw file
  1. <?php
  2. namespace PhpBrew;
  3. use PhpBrew\Utils;
  4. use Exception;
  5. /**
  6. $variants = new Variants;
  7. $variants->add('mysql');
  8. $variants->add('pdo', '/custom/prefix');
  9. $variants->build( );
  10. */
  11. class Variants
  12. {
  13. /**
  14. * target php version
  15. */
  16. public $version;
  17. /**
  18. * available variants
  19. */
  20. public $variants = array();
  21. /**
  22. * used features
  23. */
  24. public $use = array();
  25. /**
  26. * default use variants
  27. */
  28. public $defaultUse = array(
  29. 'pdo' => 1,
  30. 'bz2' => 1,
  31. 'cli' => 1,
  32. 'fpm' => 1,
  33. 'bz2' => 1,
  34. 'posix' => 1,
  35. 'calendar' => 1,
  36. 'sockets' => 1,
  37. 'readline' => 1,
  38. );
  39. public $disables = array();
  40. public $conflicts = array(
  41. // PHP Version lower than 5.4.0 can only built one SAPI at the same time.
  42. 'apxs2' => array( 'fpm','cgi' ),
  43. );
  44. public function __construct()
  45. {
  46. $self = $this;
  47. $this->variants['calendar'] = function() {
  48. return '--enable-calendar';
  49. };
  50. $this->variants['posix'] = function() {
  51. return '--enable-posix';
  52. };
  53. $this->variants['embed'] = function() {
  54. return '--enable-embed';
  55. };
  56. $this->variants['readline'] = function() {
  57. $opts = array();
  58. if( $prefix = Utils::find_include_prefix( 'readline' . DIRECTORY_SEPARATOR . 'readline.h') ) {
  59. $opts[] = '--with-readline=' . $prefix;
  60. }
  61. if( $prefix = Utils::find_include_prefix('editline' . DIRECTORY_SEPARATOR . 'readline.h') ) {
  62. $opts[] = '--with-libedit=' . $prefix;
  63. }
  64. return $opts;
  65. };
  66. // init variant builders
  67. $this->variants['pdo'] = function() {
  68. return '--enable-pdo';
  69. };
  70. $this->variants['gd'] = function() use($self) {
  71. $opts = array();
  72. if( $prefix = Utils::find_include_prefix('gd.h') ) {
  73. $opts[] = '--with-gd=' . $prefix;
  74. $opts[] = '--enable-gd-native-ttf';
  75. }
  76. else {
  77. echo "** libgd not found.\n";
  78. }
  79. if( $p = Utils::find_include_prefix('jpeglib.h') ) {
  80. $opts[] = '--with-jpeg-dir=' . $p;
  81. }
  82. if( $p = Utils::find_include_prefix('png.h') ) {
  83. $opts[] = '--with-png-dir=' . $p;
  84. }
  85. return $opts;
  86. };
  87. $this->variants['openssl'] = function() use($self) {
  88. $prefix = Utils::get_pkgconfig_prefix('openssl');
  89. if( $prefix )
  90. return '--with-openssl=' . $prefix;
  91. echo "** openssl not found.\n";
  92. };
  93. /*
  94. --with-mysql[=DIR] Include MySQL support. DIR is the MySQL base
  95. directory. If mysqlnd is passed as DIR,
  96. the MySQL native driver will be used [/usr/local]
  97. --with-mysqli[=FILE] Include MySQLi support. FILE is the path
  98. to mysql_config. If mysqlnd is passed as FILE,
  99. the MySQL native driver will be used [mysql_config]
  100. --with-pdo-mysql[=DIR] PDO: MySQL support. DIR is the MySQL base directoy
  101. If mysqlnd is passed as DIR, the MySQL native
  102. native driver will be used [/usr/local]
  103. --with-mysql // deprecated
  104. */
  105. $this->variants['mysql'] = function( $prefix = 'mysqlnd' ) use ($self) {
  106. $opts = array(
  107. "--with-mysql=$prefix",
  108. "--with-mysqli=$prefix"
  109. );
  110. if( isset($self->use['pdo']) ) {
  111. $opts[] = "--with-pdo-mysql=$prefix";
  112. }
  113. return $opts;
  114. };
  115. $this->variants['fpm'] = function() use ($self) {
  116. return '--enable-fpm';
  117. };
  118. $this->variants['sqlite'] = function( $prefix = null ) use ($self) {
  119. $opts = array(
  120. '--with-sqlite3' . ($prefix ? "=$prefix" : '')
  121. );
  122. if( isset($self->use['pdo']) )
  123. $opts[] = '--with-pdo-sqlite';
  124. return $opts;
  125. };
  126. $this->variants['pgsql'] = function($prefix = null) use($self) {
  127. $opts = array();
  128. $opts[] = '--with-pgsql' . ($prefix ? "=$prefix" : '');
  129. if( isset($self->use['pdo']) )
  130. $opts[] = '--with-pdo-pgsql';
  131. return $opts;
  132. };
  133. $this->variants['cli'] = function() {
  134. return '--enable-cli';
  135. };
  136. $this->variants['ftp'] = function() {
  137. return '--enable-ftp';
  138. };
  139. $this->variants['sockets'] = function() {
  140. return '--enable-sockets';
  141. };
  142. $this->variants['apxs2'] = function($prefix = null) use ($self) {
  143. $a = '--with-apxs2';
  144. $apxs = null;
  145. if( $prefix ) {
  146. $a .= '=' . $prefix;
  147. $apxs = $prefix;
  148. }
  149. if( ! $apxs ) {
  150. $apxs = Utils::findbin('apxs');
  151. }
  152. // use apxs to check module dir permission
  153. if( $apxs && $libdir = trim( Utils::pipe_execute( "$apxs -q LIBEXECDIR" ) ) ) {
  154. if( false === is_writable($libdir) ) {
  155. $msg = array();
  156. throw new Exception("Apache module dir $libdir is not writable.\nPlease consider using chmod or sudo.");
  157. }
  158. }
  159. if( $apxs && $confdir = trim( Utils::pipe_execute( "$apxs -q SYSCONFDIR" ) ) ) {
  160. if( false === is_writable($confdir) ) {
  161. $msg = array();
  162. $msg[] = "Apache conf dir $confdir is not writable for phpbrew.";
  163. $msg[] = "Please consider using chmod or sudo: ";
  164. $msg[] = " \$ sudo chmod -R og+rw $confdir";
  165. throw new Exception( join("\n", $msg ) );
  166. }
  167. }
  168. return $a;
  169. };
  170. $this->variants['debug'] = function() {
  171. return array('--enable-debug');
  172. };
  173. $this->variants['cgi'] = function() {
  174. return '--enable-cgi';
  175. };
  176. $this->variants['soap'] = function() {
  177. return '--enable-soap';
  178. };
  179. $this->variants['pcntl'] = function() {
  180. return '--enable-pcntl';
  181. };
  182. $this->variants['intl'] = function() {
  183. return '--enable-intl';
  184. };
  185. $this->variants['imap'] = function() {
  186. return '--with-imap-ssl';
  187. };
  188. $this->variants['kerberos'] = function() {
  189. return '--with-kerberos';
  190. };
  191. $this->variants['iconv'] = function() {
  192. // detect include path for iconv.h
  193. if( $prefix = Utils::find_include_prefix('iconv.h') ) {
  194. return "--with-iconv";
  195. // return "--with-iconv=$prefix";
  196. }
  197. };
  198. $this->variants['bz2'] = function($prefix = null) {
  199. if( ! $prefix
  200. && $prefix = Utils::find_include_prefix('bzlib.h') ) {
  201. return '--with-bz2=' . $prefix;
  202. }
  203. };
  204. $this->variants['ipc'] = function() {
  205. return array(
  206. '--enable-shmop',
  207. '--enable-sysvsem',
  208. '--enable-sysvshm',
  209. '--enable-sysvmsg',
  210. );
  211. };
  212. // '--with-mcrypt=/usr',
  213. /**
  214. * default features
  215. **/
  216. foreach( $this->defaultUse as $u => $v ) {
  217. $this->enable($u);
  218. }
  219. }
  220. public function isDefault($feature)
  221. {
  222. return isset($this->defaultUse[$feature]);
  223. }
  224. private function _getConflict($feature)
  225. {
  226. if( isset( $this->conflicts[ $feature ] ) ) {
  227. $conflicts = array();
  228. foreach( $this->conflicts[ $feature ] as $f ) {
  229. if( $this->isUsing($f) )
  230. $conflicts[] = $f;
  231. }
  232. return $conflicts;
  233. }
  234. return false;
  235. }
  236. public function checkConflicts()
  237. {
  238. if( isset($this->use['apxs2'])
  239. && version_compare( $this->version , 'php-5.4.0' ) < 0 )
  240. {
  241. if( $conflicts = $this->_getConflict('apxs2') ) {
  242. $msgs = array();
  243. $msgs[] = "PHP Version lower than 5.4.0 can only build one SAPI at the same time.";
  244. $msgs[] = "+apxs2 is in conflict with " . join(',',$conflicts);
  245. foreach( $conflicts as $c ) {
  246. $msgs[] = "Disabling $c";
  247. unset($this->use[$c]);
  248. }
  249. $this->disables[] = '--disable-fpm';
  250. $this->disables[] = '--disable-cgi';
  251. // $this->disables[] = '--disable-cli';
  252. echo join("\n",$msgs) . "\n";
  253. }
  254. }
  255. return true;
  256. }
  257. public function enable($feature,$value = true )
  258. {
  259. $this->use[ $feature ] = $value;
  260. }
  261. public function isUsing($feature)
  262. {
  263. return isset( $this->use[ $feature ] );
  264. }
  265. public function checkPkgPrefix($option,$pkgName)
  266. {
  267. $prefix = Utils::get_pkgconfig_prefix($pkgName);
  268. return $prefix ? $option . '=' . $prefix : $option;
  269. }
  270. public function getVariantNames()
  271. {
  272. return array_keys( $this->variants );
  273. }
  274. public function buildVariant($feature,$userValue = null)
  275. {
  276. if( isset( $this->variants[ $feature ] ) ) {
  277. $func = $this->variants[ $feature ];
  278. $args = array();
  279. if( is_string($userValue) )
  280. $args[] = $userValue;
  281. return (array) call_user_func_array($func,$args);
  282. }
  283. else {
  284. throw new Exception("Variant $feature is not defined.");
  285. }
  286. }
  287. /**
  288. * build configure options
  289. */
  290. public function build()
  291. {
  292. return $this->buildOptions();
  293. }
  294. public function buildOptions()
  295. {
  296. // build common options
  297. $opts = array(
  298. '--disable-all',
  299. '--enable-bcmath',
  300. '--enable-ctype',
  301. '--enable-dom',
  302. '--enable-exif',
  303. '--enable-fileinfo',
  304. '--enable-filter',
  305. '--enable-hash',
  306. '--enable-json',
  307. '--enable-libxml',
  308. '--enable-mbregex',
  309. '--enable-mbstring',
  310. '--enable-phar',
  311. '--enable-session',
  312. '--enable-short-tags',
  313. '--enable-simplexml',
  314. '--enable-sockets',
  315. '--enable-tokenizer',
  316. '--enable-xml',
  317. '--enable-xmlreader',
  318. '--enable-xmlwriter',
  319. '--enable-zip',
  320. '--with-xsl',
  321. '--with-tidy',
  322. '--with-xmlrpc',
  323. '--with-mhash',
  324. '--with-pcre-regex',
  325. );
  326. if( $prefix = Utils::find_include_prefix('zlib.h') ) {
  327. $opts[] = '--with-zlib=' . $prefix;
  328. }
  329. if( $prefix = Utils::get_pkgconfig_prefix('libxml') ) {
  330. $opts[] = '--with-libxml-dir=' . $prefix;
  331. }
  332. if( $prefix = Utils::get_pkgconfig_prefix('libcurl') ) {
  333. $opts[] = '--with-curl=' . $prefix;
  334. }
  335. if( $prefix = Utils::find_include_prefix('libintl.h') ) {
  336. $opts[] = '--with-gettext=' . $prefix;
  337. }
  338. $this->checkConflicts();
  339. foreach( $this->use as $feature => $userValue ) {
  340. if( $options = $this->buildVariant( $feature , $userValue ) ) {
  341. $opts = array_merge( $opts, $options );
  342. }
  343. }
  344. foreach( $this->disables as $d ) {
  345. $opts[] = $d;
  346. }
  347. /*
  348. $opts = array_merge( $opts ,
  349. $this->getVersionOptions($version) );
  350. */
  351. return $opts;
  352. }
  353. /**
  354. * get available variants for $version
  355. *
  356. * @param string $version version string
  357. */
  358. public function getAvailableVariants($version)
  359. {
  360. // xxx: use version_compare to merge config options
  361. if( isset($this->variants[$version]) )
  362. return $this->variants;
  363. /** try to match regular expressions */
  364. foreach( $this->variants as $k => $variants ) {
  365. if( strpos($k,'/') === 0 ) {
  366. if( preg_match( $k , $version ) )
  367. return $variants;
  368. }
  369. }
  370. }
  371. public function getVariantOptions($version,$variant)
  372. {
  373. $variants = $this->getAvailableVariants($version);
  374. // todo:
  375. }
  376. public function getVersionOptions($version)
  377. {
  378. $options = array();
  379. $defs = array();
  380. $defs['= php-5.2'] = array();
  381. $defs['= php-5.3'] = array();
  382. $defs['= php-5.4.0RC7'] = array();
  383. foreach($defs as $versionExp => $versionOptions ) {
  384. if( preg_match('/^([=<>]+)\s+(\S+)$/',$versionExp,$regs) ) {
  385. list($orig,$op,$rVersion) = $regs;
  386. switch($op)
  387. {
  388. case '=':
  389. if( version_compare($version,$rVersion) === 0 ) {
  390. $options = array_merge( $options, $versionOptions );
  391. }
  392. break;
  393. case '>':
  394. if( version_compare($version,$rVersion) > 0 ) {
  395. }
  396. break;
  397. case '<':
  398. if( version_compare($version,$rVersion) < 0 ) {
  399. }
  400. break;
  401. }
  402. }
  403. else {
  404. throw new Exception("Unsupported format $versionExp");
  405. }
  406. }
  407. return $options;
  408. }
  409. }