public function check(Build $build) { $apxs = $build->getVariant('apxs2'); // trying to find apxs binary in case it wasn't explicitly specified (+apxs variant without path) if ($apxs === true) { $apxs = Utils::findbin('apxs'); $this->logger->debug("Found apxs2 binary: {$apxs}"); } if (!is_executable($apxs)) { throw new Exception("apxs binary is not executable: {$apxs}"); } // use apxs to check module dir permission if ($apxs && ($libdir = trim(Utils::pipeExecute("{$apxs} -q LIBEXECDIR")))) { if (false === is_writable($libdir)) { $this->logger->error("Apache module dir {$libdir} is not writable.\nPlease consider using chmod to change the folder permission:"); $this->logger->error(" \$ sudo chmod -R oga+rw {$libdir}"); $this->logger->error("Warnings: the command above is not safe for public systems. please use with discretion."); throw new Exception(); } } if ($apxs && ($confdir = trim(Utils::pipeExecute("{$apxs} -q SYSCONFDIR")))) { if (false === is_writable($confdir)) { $this->logger->error("Apache conf dir {$confdir} is not writable for phpbrew."); $this->logger->error("Please consider using chmod to change the folder permission: "); $this->logger->error(" \$ sudo chmod -R oga+rw {$confdir}"); $this->logger->error("Warnings: the command above is not safe for public systems. please use with discretion."); throw new Exception(); } } }
public function testPatch() { if (PHP_OS !== "Darwin") { return $this->markTestSkipped('openssl DSO patch test only runs on darwin platform'); } $logger = new Logger(); $logger->setQuiet(); $fromVersion = '5.5.17'; $sourceFixtureDirectory = getenv('PHPBREW_FIXTURES_PHP_DIR') . DIRECTORY_SEPARATOR . $fromVersion; $sourceDirectory = getenv('PHPBREW_BUILD_PHP_DIR'); $this->setupBuildDirectory($fromVersion); $build = new Build($fromVersion); $build->setSourceDirectory($sourceDirectory); $build->enableVariant('openssl'); $this->assertTrue($build->hasVariant('openssl'), 'openssl enabled'); $patch = new OpenSSLDSOPatch(); $matched = $patch->match($build, $logger); $this->assertTrue($matched, 'patch matched'); $patchedCount = $patch->apply($build, $logger); $this->assertEquals(10, $patchedCount); /* We can't assume the file equals because the test may be run on different platform and openssl may be installed into different locations. $sourceExpectedDirectory = getenv('PHPBREW_EXPECTED_PHP_DIR') . DIRECTORY_SEPARATOR . '5.5.17-openssl-dso-patch'; $this->assertFileEquals($sourceExpectedDirectory. '/Makefile', $sourceDirectory . '/Makefile'); */ }
public function install(Build $build) { $this->info('Installing...'); if ($this->options->sudo) { $cmd = new CommandBuilder('sudo make install'); if (!$this->options->dryrun) { $code = $cmd->passthru($lastline); if ($code !== 0) { throw new SystemCommandException("Install failed: {$lastline}", $build, $build->getBuildLogPath()); } } } else { $cmd = new CommandBuilder('make install'); $cmd->setAppendLog(true); $cmd->setLogPath($build->getBuildLogPath()); $cmd->setStdout($this->options->{'stdout'}); if (!$this->options->dryrun) { $code = $cmd->execute($lastline); if ($code !== 0) { throw new SystemCommandException("Install failed: {$lastline}", $build, $build->getBuildLogPath()); } } } $build->setState(Build::STATE_INSTALL); }
public function testPatch() { $logger = new Logger(); $logger->setQuiet(); $fromVersion = '5.3.29'; $sourceFixtureDirectory = getenv('PHPBREW_FIXTURES_PHP_DIR') . DIRECTORY_SEPARATOR . $fromVersion; $sourceDirectory = getenv('PHPBREW_BUILD_PHP_DIR'); if (!is_dir($sourceDirectory)) { return $this->markTestSkipped("{$sourceDirectory} does not exist."); } // Copy the source Makefile to the Makefile // copy($sourceFixtureDirectory . '/Makefile', $sourceDirectory . '/Makefile'); $this->setupBuildDirectory($fromVersion); $build = new Build($fromVersion); $build->setSourceDirectory($sourceDirectory); $build->enableVariant('intl'); $this->assertTrue($build->hasVariant('intl'), 'intl enabled'); $patch = new IntlWith64bitPatch(); $matched = $patch->match($build, $logger); $this->assertTrue($matched, 'patch matched'); $patchedCount = $patch->apply($build, $logger); $this->assertEquals(3, $patchedCount); $sourceExpectedDirectory = getenv('PHPBREW_EXPECTED_PHP_DIR') . DIRECTORY_SEPARATOR . $fromVersion; $this->assertFileEquals($sourceExpectedDirectory . '/Makefile', $sourceDirectory . '/Makefile'); }
public function check(Build $build) { $apxs = $build->getVariant('apxs2'); // trying to find apxs binary in case it wasn't explicitly specified (+apxs variant without path) if ($apxs === true) { $apxs = Utils::findbin('apxs'); $this->logger->debug("Found apxs2 binary: {$apxs}"); } if (!is_executable($apxs)) { throw new Exception("apxs binary is not executable: {$apxs}"); } // use apxs to check module dir permission if ($apxs && ($libdir = trim(Utils::pipeExecute("{$apxs} -q LIBEXECDIR")))) { if (false === is_writable($libdir)) { throw new Exception("Apache module dir {$libdir} is not writable.\nPlease consider using chmod or sudo."); } } if ($apxs && ($confdir = trim(Utils::pipeExecute("{$apxs} -q SYSCONFDIR")))) { if (false === is_writable($confdir)) { $msg = array(); $msg[] = "Apache conf dir {$confdir} is not writable for phpbrew."; $msg[] = "Please consider using chmod or sudo: "; $msg[] = " \$ sudo chmod -R og+rw {$confdir}"; throw new Exception(join("\n", $msg)); } } }
public function run(Build $build, $targets = array()) { if ($build->getState() >= Build::STATE_BUILD) { $this->info("===> Already built, skipping..."); return; } $this->info("===> Building..."); $cmd = new CommandBuilder('make'); $cmd->setAppendLog(true); $cmd->setLogPath($build->getBuildLogPath()); $cmd->setStdout($this->options->{'stdout'}); if (!empty($targets)) { foreach ($targets as $t) { $cmd->addArg($t); } } if ($this->options->nice) { $cmd->nice($this->options->nice); } if ($makeJobs = $this->options->{'jobs'}) { $cmd->addArg("-j{$makeJobs}"); } $this->debug($cmd->getCommand()); if (!$this->options->dryrun) { $startTime = microtime(true); $code = $cmd->execute(); if ($code != 0) { throw new SystemCommandException('Make failed.', $build, $build->getBuildLogPath()); } $buildTime = round((microtime(true) - $startTime) / 60, 1); $this->info("Build finished: {$buildTime} minutes."); } $build->setState(Build::STATE_BUILD); }
/** * Unpacks the source tarball file. * * @param string $targetFilePath absolute file path * @param string $extractDir (the build dir) */ public function extract(Build $build, $targetFilePath, $extractDir = null) { if (empty($extractDir)) { $extractDir = dirname($targetFilePath); } $extractDirTemp = $extractDir . DIRECTORY_SEPARATOR . 'tmp.' . time(); if (!file_exists($extractDirTemp)) { mkdir($extractDirTemp, 0755, true); } // This converts: '/opt/phpbrew/distfiles/php-7.0.2.tar.bz2' // to just '/opt/phpbrew/tmp/distfiles/php-7.0.2' $distBasename = preg_replace('#\\.tar\\.(gz|bz2)$#', '', basename($targetFilePath)); $extractedDirTemp = $extractDirTemp . DIRECTORY_SEPARATOR . $distBasename; $extractedDir = $extractDir . DIRECTORY_SEPARATOR . $build->getName(); if ($build->getState() >= Build::STATE_EXTRACT && file_exists($extractedDir . DIRECTORY_SEPARATOR . 'configure')) { $this->info('===> Distribution file was successfully extracted, skipping...'); return $extractedDir; } // NOTICE: Always extract to tmp directory prevent incomplete extraction $this->info("===> Extracting {$targetFilePath} to {$extractedDirTemp}"); $lastline = system('tar -C ' . escapeshellarg($extractDirTemp) . ' -xf ' . escapeshellarg($targetFilePath), $ret); if ($ret !== 0) { throw new SystemCommandException("Extract failed: {$lastline}", $build); } clearstatcache(true); if (!is_dir($extractedDirTemp)) { // retry with github extracted dir path $extractedDirTemp = $extractDirTemp . DIRECTORY_SEPARATOR . 'php-src-' . $distBasename; if (!is_dir($extractedDirTemp)) { throw new SystemCommandException("Unable to find {$extractedDirTemp}", $build); } } if (is_dir($extractedDir)) { $this->info("===> Found existing build directory, removing {$extractedDir} ..."); $lastline = system('rm -rf ' . escapeshellarg($extractedDir), $ret); if ($ret !== 0) { throw new SystemCommandException("Unable to remove {$extractedDir}: {$lastline}", $build); } } $this->info("===> Moving {$extractedDirTemp} to {$extractedDir}"); if (!rename($extractedDirTemp, $extractedDir)) { throw new SystemCommandException("Unable to move {$extractedDirTemp} to {$extractedDir}", $build); } @rmdir($extractDirTemp); $build->setState(Build::STATE_EXTRACT); return $extractedDir; /* * XXX: unless we have a fast way to verify the extraction. if ($this->options->force || ! file_exists($extractedDir . DIRECTORY_SEPARATOR . 'configure')) { $this->info("===> Extracting $targetFilePath..."); system("tar -C $dir -xjf $targetFilePath", $ret); if ($ret != 0) { die('Extract failed.'); } } else { $this->info("Found existing $extractedDir, Skip extracting."); } */ }
public function deregister(Build $build) { $file = $this->baseDir . DIRECTORY_SEPARATOR . $build->getName(); if (file_exists($file)) { unlink($file); return true; } return false; }
public function testApply() { $version = '5.3.29'; $fixture = new TemporaryFileFixture($this, getenv('PHPBREW_FIXTURES_PHP_DIR') . "/{$version}/Makefile.in"); $fixture->withFile('Makefile', function ($self, $fixturePath) use($version) { $build = new Build($version); $build->setSourceDirectory(dirname($fixturePath)); $patch = new RegexpPatch($self->logger, $build, array(basename($fixturePath)), array(RegexpPatchRule::always('/LIBTOOL/', ''))); $patch->apply(); $self->assertFileEquals($fixturePath, getenv('PHPBREW_EXPECTED_PHP_DIR') . '/5.3.29/Makefile.in'); }); }
/** * Unpacks the source tarball file. * * @param string $targetFilePath absolute file path */ public function extract(Build $build, $targetFilePath, $extractDir = NULL) { $extractDirTemp = Config::getTempFileDir(); if (!$extractDir) { $extractDir = dirname($targetFilePath); } $extractedDirTemp = $extractDirTemp . DIRECTORY_SEPARATOR . preg_replace('#\\.tar\\.(gz|bz2)$#', '', basename($targetFilePath)); $extractedDir = $extractDir . DIRECTORY_SEPARATOR . $build->getName(); if ($build->getState() >= Build::STATE_EXTRACT && file_exists($extractedDir . DIRECTORY_SEPARATOR . 'configure')) { $this->info("===> Distribution file was successfully extracted, skipping..."); return $extractedDir; } // NOTICE: Always extract to prevent incomplete extraction $this->info("===> Extracting {$targetFilePath} to {$extractedDirTemp}"); system("tar -C {$extractDirTemp} -xf {$targetFilePath}", $ret); if ($ret != 0) { throw new RuntimeException('Extract failed.'); } clearstatcache(true); if (!is_dir($extractedDirTemp)) { // retry with github extracted dir path $extractedDirTemp = $extractDirTemp . DIRECTORY_SEPARATOR . 'php-src-' . preg_replace('#\\.tar\\.(gz|bz2)$#', '', basename($targetFilePath)); if (!is_dir($extractedDirTemp)) { throw new RuntimeException("Unable to find {$extractedDirTemp}"); } } if (is_dir($extractedDir)) { $this->info("===> Removing {$extractedDir}"); system("rm -rf {$extractedDir}", $ret); if ($ret !== 0) { throw new RuntimeException("Unable to remove {$extractedDir}."); } } $this->info("===> Moving {$extractedDirTemp} to {$extractedDir}"); if (!rename($extractedDirTemp, $extractedDir)) { throw new RuntimeException("Unable to move {$extractedDirTemp} to {$extractedDir}"); } $build->setState(Build::STATE_EXTRACT); return $extractedDir; /* * XXX: unless we have a fast way to verify the extraction. if ($this->options->force || ! file_exists($extractedDir . DIRECTORY_SEPARATOR . 'configure')) { $this->info("===> Extracting $targetFilePath..."); system("tar -C $dir -xjf $targetFilePath", $ret); if ($ret != 0) { die('Extract failed.'); } } else { $this->info("Found existing $extractedDir, Skip extracting."); } */ }
public function install(Build $build) { $this->info("Installing..."); $cmd = new CommandBuilder('make install'); $cmd->setAppendLog(true); $cmd->setLogPath($build->getBuildLogPath()); $cmd->setStdout($this->options->{'stdout'}); if (!$this->options->dryrun) { $code = $cmd->execute(); if ($code != 0) { throw new SystemCommandException('Install failed.', $build->getBuildLogPath()); } } $build->setState(Build::STATE_INSTALL); }
public function run(Build $build, $nice = null) { $this->info("Testing..."); $cmd = new CommandBuilder('make test'); if ($nice) { $cmd->nice($nice); } $cmd->setAppendLog(true); $cmd->setLogPath($build->getBuildLogPath()); $cmd->setStdout($this->options->{'stdout'}); $this->debug('' . $cmd); $code = $cmd->execute(); if ($code != 0) { throw new RuntimeException('Test failed.'); } }
public function run(Build $build, $nice = null) { $this->info('===> Running tests...'); $cmd = new CommandBuilder('make test'); if ($nice) { $cmd->nice($nice); } $cmd->setAppendLog(true); $cmd->setLogPath($build->getBuildLogPath()); $cmd->setStdout($this->options->{'stdout'}); putenv('NO_INTERACTION=1'); $this->debug('' . $cmd); $code = $cmd->execute($lastline); if ($code !== 0) { throw new SystemCommandException("Test failed: {$lastline}", $build); } }
public function run(Build $build = NULL) { $dirs = array(); $dirs[] = Config::getPhpbrewRoot(); $dirs[] = Config::getPhpbrewHome(); $dirs[] = Config::getBuildDir(); $dirs[] = Config::getDistFileDir(); $dirs[] = Config::getVariantsDir(); if ($build) { $dirs[] = Config::getInstallPrefix() . DIRECTORY_SEPARATOR . $build->getName(); } foreach ($dirs as $dir) { if (!file_exists($dir)) { $this->logger->debug("Creating directory {$dir}"); mkdir($dir, 0755, true); } } }
public function execute($version) { $buildDir = Config::getBuildDir() . DIRECTORY_SEPARATOR . $version; if ($this->options->all) { if (!file_exists($buildDir)) { $this->logger->info("Source directory " . $buildDir . " does not exist."); } else { $this->logger->info("Source directory " . $buildDir . " found, deleting..."); Utils::recursive_unlink($buildDir, $this->logger); } } else { $make = new MakeTask($this->logger); $make->setQuiet(); $build = new Build($version); $build->setSourceDirectory($buildDir); if ($make->clean($build)) { $this->logger->info("Distribution is cleaned up. Woof! "); } } }
public function run(Build $build) { if (!file_exists($build->getSourceDirectory() . DIRECTORY_SEPARATOR . 'configure')) { $this->debug("configure file not found, running './buildconf --force'..."); $lastline = system('./buildconf --force', $status); if ($status !== 0) { throw new SystemCommandException("buildconf error: {$lastline}", $build); } } foreach ((array) $this->options->patch as $patchPath) { // copy patch file to here $this->info("===> Applying patch file from {$patchPath} ..."); // Search for strip parameter for ($i = 0; $i <= 16; ++$i) { ob_start(); system("patch -p{$i} --dry-run < {$patchPath}", $return); ob_end_clean(); if ($return === 0) { system("patch -p{$i} < {$patchPath}"); break; } } } // let's apply patch for libphp{php version}.so (apxs) if ($build->isEnabledVariant('apxs2')) { $apxs2Checker = new \PhpBrew\Tasks\Apxs2CheckTask($this->logger); $apxs2Checker->check($build, $this->options); } if (!$this->options->{'no-patch'}) { $this->logger->info('===> Checking patches...'); $patches = array(); $patches[] = new Apache2ModuleNamePatch(); foreach ($patches as $patch) { $this->logger->info('Checking patch for ' . $patch->desc()); if ($patch->match($build, $this->logger)) { $patched = $patch->apply($build, $this->logger); $this->logger->info("{$patched} changes patched."); } } } }
public function check(Build $build) { $apxs = $build->getVariant('apxs2'); if (!$apxs) { $apxs = Utils::findbin('apxs'); } $this->logger->debug("Found apxs2 sbin: {$apxs}"); // use apxs to check module dir permission if ($apxs && ($libdir = trim(Utils::pipeExecute("{$apxs} -q LIBEXECDIR")))) { if (false === is_writable($libdir)) { $msg = array(); throw new Exception("Apache module dir {$libdir} is not writable.\nPlease consider using chmod or sudo."); } } if ($apxs && ($confdir = trim(Utils::pipeExecute("{$apxs} -q SYSCONFDIR")))) { if (false === is_writable($confdir)) { $msg = array(); $msg[] = "Apache conf dir {$confdir} is not writable for phpbrew."; $msg[] = "Please consider using chmod or sudo: "; $msg[] = " \$ sudo chmod -R og+rw {$confdir}"; throw new Exception(join("\n", $msg)); } } }
public function testPatch() { $logger = new Logger(); $logger->setQuiet(); $fromVersion = '5.5.17'; $sourceFixtureDirectory = getenv('PHPBREW_FIXTURES_PHP_DIR') . DIRECTORY_SEPARATOR . $fromVersion; $sourceDirectory = getenv('PHPBREW_BUILD_PHP_DIR'); if (!is_dir($sourceDirectory)) { return $this->markTestSkipped("{$sourceDirectory} does not exist."); } $this->setupBuildDirectory($fromVersion); $build = new Build($fromVersion); $build->setSourceDirectory($sourceDirectory); $build->enableVariant('apxs2'); $this->assertTrue($build->hasVariant('apxs2'), 'apxs2 enabled'); $patch = new Apache2ModuleNamePatch(); $matched = $patch->match($build, $logger); $this->assertTrue($matched, 'patch matched'); $patchedCount = $patch->apply($build, $logger); $this->assertEquals(107, $patchedCount); $sourceExpectedDirectory = getenv('PHPBREW_EXPECTED_PHP_DIR') . DIRECTORY_SEPARATOR . '5.5.17-apxs-patch'; $this->assertFileEquals($sourceExpectedDirectory . '/Makefile.global', $sourceDirectory . '/Makefile.global'); $this->assertFileEquals($sourceExpectedDirectory . '/configure', $sourceDirectory . '/configure'); }
public function testMysqlPdoVariant() { $variants = new PhpBrew\VariantBuilder(); ok($variants); $build = new PhpBrew\Build('5.3.0'); $build->enableVariant('pdo'); $build->enableVariant('mysql'); $build->enableVariant('sqlite'); $build->resolveVariants(); $options = $variants->build($build); $this->assertContains('--enable-pdo', $options); $this->assertContains('--with-mysql=mysqlnd', $options); $this->assertContains('--with-mysqli=mysqlnd', $options); $this->assertContains('--with-pdo-mysql=mysqlnd', $options); $this->assertContains('--with-pdo-sqlite', $options); }
public function execute($version) { if (extension_loaded('posix') && posix_getuid() === 0) { $this->logger->warn("*WARNING* You're runing phpbrew as root/sudo. Unless you're going to install\nsystem-wide phpbrew or this might cause problems."); sleep(3); } $distUrl = null; $versionInfo = array(); $releaseList = ReleaseList::getReadyInstance($this->options); $versionDslParser = new VersionDslParser(); $clean = new MakeTask($this->logger, $this->options); $clean->setQuiet(); if ($root = $this->options->root) { Config::setPhpbrewRoot($root); } if ($home = $this->options->home) { Config::setPhpbrewHome($home); } if ('latest' === strtolower($version)) { $version = $releaseList->getLatestVersion(); } // this should point to master or the latest version branch yet to be released if ('next' === strtolower($version)) { $version = 'github.com/php/php-src:master'; } if ($info = $versionDslParser->parse($version)) { $version = $info['version']; $distUrl = $info['url']; // always redownload when installing from github master // beware to keep this behavior after clean up the TODO below $this->options['force']->setValue(true); } else { // TODO ↓ clean later ↓ d.d.d versions should be part of the DSL too $version = preg_replace('/^php-/', '', $version); $versionInfo = $releaseList->getVersion($version); if (!$versionInfo) { throw new Exception("Version {$version} not found."); } $version = $versionInfo['version']; $distUrlPolicy = new DistributionUrlPolicy(); if ($this->options->mirror) { $distUrlPolicy->setMirrorSite($this->options->mirror); } $distUrl = $distUrlPolicy->buildUrl($version, $versionInfo['filename'], $versionInfo['museum']); } // get options and variants for building php // and skip the first argument since it's the target version. $args = func_get_args(); array_shift($args); // shift the version name $semanticOptions = $this->parseSemanticOptions($args); $buildAs = isset($semanticOptions['as']) ? $semanticOptions['as'] : $this->options->name; $buildLike = isset($semanticOptions['like']) ? $semanticOptions['like'] : $this->options->like; // convert patch to realpath if ($this->options->patch) { $patchPaths = array(); foreach ($this->options->patch as $patch) { /* @var \SplFileInfo $patch */ $patchPath = realpath($patch); if ($patchPath !== false) { $patchPaths[(string) $patch] = $patchPath; } } // rewrite patch paths $this->options->keys['patch']->value = $patchPaths; } // Initialize the build object, contains the information to build php. $build = new Build($version, $buildAs); $installPrefix = Config::getInstallPrefix() . DIRECTORY_SEPARATOR . $build->getName(); if (!file_exists($installPrefix)) { mkdir($installPrefix, 0755, true); } $build->setInstallPrefix($installPrefix); // find inherited variants if ($buildLike) { if ($parentBuild = Build::findByName($buildLike)) { $this->logger->info("===> Loading build settings from {$buildLike}"); $build->loadVariantInfo($parentBuild->settings->toArray()); } } $msg = "===> phpbrew will now build {$build->getVersion()}"; if ($buildLike) { $msg .= ' using variants from ' . $buildLike; } if (isset($semanticOptions['using'])) { $msg .= ' plus custom variants: ' . implode(', ', $semanticOptions['using']); $args = array_merge($args, $semanticOptions['using']); } if ($buildAs) { $msg .= ' as ' . $buildAs; } $this->logger->info($msg); if (!empty($args)) { $this->logger->debug("---> Parsing variants from command arguments '" . implode(' ', $args) . "'"); } // ['extra_options'] => the extra options to be passed to ./configure command // ['enabled_variants'] => enabeld variants // ['disabled_variants'] => disabled variants $variantInfo = VariantParser::parseCommandArguments($args); $build->loadVariantInfo($variantInfo); // load again // assume +default variant if no build config is given and warn about that if (!$variantInfo['enabled_variants']) { $build->setBuildSettings(new DefaultBuildSettings()); $this->logger->notice("You haven't set any variant. A default set of extensions will be installed for the minimum requirement:"); $this->logger->notice('[' . implode(', ', array_keys($build->getVariants())) . ']'); $this->logger->notice("Please run 'phpbrew variants' for more information.\n"); } if (preg_match('/5\\.3\\./', $version)) { $this->logger->notice('PHP 5.3 requires +intl, enabled by default.'); $build->enableVariant('intl'); } // always add +xml by default unless --without-pear is present // TODO: This can be done by "-pear" if (!in_array('--without-pear', $variantInfo['extra_options'])) { $build->enableVariant('xml'); } $this->logger->info('===> Loading and resolving variants...'); $removedVariants = $build->loadVariantInfo($variantInfo); if (!empty($removedVariants)) { $this->logger->debug('Removed variants: ' . implode(',', $removedVariants)); } $prepareTask = new PrepareDirectoryTask($this->logger, $this->options); $prepareTask->run($build); // Move to to build directory, because we are going to download distribution. $buildDir = $this->options->{'build-dir'} ?: Config::getBuildDir(); if (!file_exists($buildDir)) { mkdir($buildDir, 0755, true); } $variantBuilder = new VariantBuilder(); $configureOptions = $variantBuilder->build($build); $distFileDir = Config::getDistFileDir(); $downloadTask = new DownloadTask($this->logger, $this->options); $targetFilePath = $downloadTask->download($distUrl, $distFileDir, isset($versionInfo['md5']) ? $versionInfo['md5'] : null); if (!file_exists($targetFilePath)) { throw new SystemCommandException("Download failed, {$targetFilePath} does not exist.", $build); } unset($downloadTask); $extractTask = new ExtractTask($this->logger, $this->options); $targetDir = $extractTask->extract($build, $targetFilePath, $buildDir); if (!file_exists($targetDir)) { throw new SystemCommandException("Extract failed, {$targetDir} does not exist.", $build); } unset($extractTask); // Update build source directory $this->logger->debug('Source Directory: ' . realpath($targetDir)); $build->setSourceDirectory($targetDir); if (!$this->options->{'no-clean'} && file_exists($targetDir . DIRECTORY_SEPARATOR . 'Makefile')) { $this->logger->info('Found existing Makefile, running make clean to ensure everything will be rebuilt.'); $this->logger->info("You can append --no-clean option after the install command if you don't want to rebuild."); $clean->clean($build); } // Change directory to the downloaded source directory. chdir($targetDir); // Write variants info. $variantInfoFile = $build->getInstallPrefix() . DIRECTORY_SEPARATOR . 'phpbrew.variants'; $this->logger->debug("Writing variant info to {$variantInfoFile}"); if (false === $build->writeVariantInfoFile($variantInfoFile)) { $this->logger->warn("Can't store variant info."); } $buildLogFile = $build->getBuildLogPath(); if (!$this->options->{'no-configure'}) { $configureTask = new BeforeConfigureTask($this->logger, $this->options); $configureTask->run($build); unset($configureTask); // trigger __destruct $configureTask = new ConfigureTask($this->logger, $this->options); $configureTask->run($build, $configureOptions); unset($configureTask); // trigger __destruct $configureTask = new AfterConfigureTask($this->logger, $this->options); $configureTask->run($build); unset($configureTask); // trigger __destruct } $buildTask = new BuildTask($this->logger, $this->options); $buildTask->run($build); unset($buildTask); // trigger __destruct if ($this->options->{'test'}) { $testTask = new TestTask($this->logger, $this->options); $testTask->run($build); unset($testTask); // trigger __destruct } if (!$this->options->{'no-install'}) { $installTask = new InstallTask($this->logger, $this->options); $installTask->install($build); unset($installTask); // trigger __destruct } if ($this->options->{'post-clean'}) { $clean->clean($build); } $dsym = new DSymTask($this->logger, $this->options); $dsym->patch($build, $this->options); // copy php-fpm config $this->logger->info('---> Creating php-fpm.conf'); $etcDirectory = $build->getEtcDirectory(); $fpmUnixSocket = $build->getInstallPrefix() . "/var/run/php-fpm.sock"; $this->installAs("{$etcDirectory}/php-fpm.conf.default", "{$etcDirectory}/php-fpm.conf"); $this->installAs("{$etcDirectory}/php-fpm.d/www.conf.default", "{$etcDirectory}/php-fpm.d/www.conf"); $patchingFiles = array("{$etcDirectory}/php-fpm.d/www.conf", "{$etcDirectory}/php-fpm.conf"); foreach ($patchingFiles as $patchingFile) { if (file_exists($patchingFile)) { $this->logger->info("---> Found {$patchingFile}"); // Patch pool listen unix // The original config was below: // // listen = 127.0.0.1:9000 // // See http://php.net/manual/en/install.fpm.configuration.php for more details $ini = file_get_contents($patchingFile); $this->logger->info("---> Patching default fpm pool listen path to {$fpmUnixSocket}"); $ini = preg_replace('/^listen = .*$/m', "listen = {$fpmUnixSocket}\n", $ini); file_put_contents($patchingFile, $ini); break; } } $this->logger->info('---> Creating php.ini'); $phpConfigPath = $build->getSourceDirectory() . DIRECTORY_SEPARATOR . ($this->options->production ? 'php.ini-production' : 'php.ini-development'); $this->logger->info("---> Copying {$phpConfigPath} "); if (file_exists($phpConfigPath) && !$this->options->dryrun) { $targetConfigPath = $etcDirectory . DIRECTORY_SEPARATOR . 'php.ini'; if (file_exists($targetConfigPath)) { $this->logger->notice("Found existing {$targetConfigPath}."); } else { // TODO: Move this to PhpConfigPatchTask // move config file to target location copy($phpConfigPath, $targetConfigPath); } if (!$this->options->{'no-patch'}) { $config = parse_ini_file($targetConfigPath, true); $configContent = file_get_contents($targetConfigPath); $patched = false; if (!isset($config['date']['timezone'])) { $this->logger->info('---> Found date.timezone is not set, patching...'); // Replace current timezone if ($timezone = ini_get('date.timezone')) { $this->logger->info("---> Found date.timezone, patching config timezone with {$timezone}"); $configContent = preg_replace('/^;?date.timezone\\s*=\\s*.*/im', "date.timezone = {$timezone}", $configContent); } $patched = true; } if (!isset($config['phar']['readonly'])) { $pharReadonly = ini_get('phar.readonly'); // 0 or "" means readonly is disabled manually if (!$pharReadonly) { $this->logger->info('---> Disabling phar.readonly option.'); $configContent = preg_replace('/^;?phar.readonly\\s*=\\s*.*/im', 'phar.readonly = 0', $configContent); } } // turn off detect_encoding for 5.3 if ($build->compareVersion('5.4') < 0) { $this->logger->info("---> Turn off detect_encoding for php 5.3.*"); $configContent = $configContent . "\ndetect_unicode = Off\n"; } file_put_contents($targetConfigPath, $configContent); } } if ($build->isEnabledVariant('pear')) { $this->logger->info('Initializing pear config...'); $home = Config::getHome(); @mkdir("{$home}/tmp/pear/temp", 0755, true); @mkdir("{$home}/tmp/pear/cache_dir", 0755, true); @mkdir("{$home}/tmp/pear/download_dir", 0755, true); system("pear config-set temp_dir {$home}/tmp/pear/temp"); system("pear config-set cache_dir {$home}/tmp/pear/cache_dir"); system("pear config-set download_dir {$home}/tmp/pear/download_dir"); $this->logger->info('Enabling pear auto-discover...'); system('pear config-set auto_discover 1'); } $this->logger->debug('Source directory: ' . $targetDir); $buildName = $build->getName(); $this->logger->info("Congratulations! Now you have PHP with {$version} as {$buildName}"); if ($build->isEnabledVariant('pdo') && $build->isEnabledVariant('mysql')) { echo <<<EOT * We found that you enabled 'mysql' variant, you might need to setup your 'pdo_mysql.default_socket' or 'mysqli.default_socket' in your php.ini file. EOT; } if (isset($targetConfigPath)) { echo <<<EOT * To configure your installed PHP further, you can edit the config file at {$targetConfigPath} EOT; } // If the bashrc file is not found, it means 'init' command didn't get // a chance to be executed. if (!file_exists(Config::getHome() . DIRECTORY_SEPARATOR . 'bashrc')) { echo <<<EOT * WARNING: You haven't run 'phpbrew init' yet! Be sure to setup your phpbrew to use your own php(s) Please run 'phpbrew init' to setup your phpbrew in place. EOT; } // If the environment variable is not defined, it means users didn't // setup ther .bashrc or .zshrc if (!getenv('PHPBREW_HOME')) { echo <<<EOT * WARNING: You haven't setup your .bashrc file to load phpbrew shell script yet! Please run 'phpbrew init' to see the steps! EOT; } echo <<<EOT To use the newly built PHP, try the line(s) below: \$ phpbrew use {$buildName} Or you can use switch command to switch your default php to {$buildName}: \$ phpbrew switch {$buildName} Enjoy! EOT; }
public function configure(\PhpBrew\Build $build) { $variantBuilder = new VariantBuilder(); $extra = $build->getExtraOptions(); if (!file_exists('configure')) { $this->logger->debug("configure file not found, running buildconf script..."); system('./buildconf') !== false or die('buildconf error'); } // build configure args // XXX: support variants $cmd = new CommandBuilder('./configure'); // putenv('CFLAGS=-O3'); $prefix = $build->getInstallPrefix(); $args[] = "--prefix=" . $prefix; $args[] = "--with-config-file-path={$prefix}/etc"; $args[] = "--with-config-file-scan-dir={$prefix}/var/db"; $args[] = "--with-pear={$prefix}/lib/php"; // this is to support pear $build->enableVariant('xml'); $variantOptions = $variantBuilder->build($build); if ($variantOptions) { $args = array_merge($args, $variantOptions); } $this->logger->debug('Enabled variants: ' . join(', ', array_keys($build->getVariants()))); $this->logger->debug('Disabled variants: ' . join(', ', array_keys($build->getDisabledVariants()))); if ($patchFiles = $this->options->patch) { foreach ($patchFiles as $patchFile) { // copy patch file to here $this->logger->info("===> Applying patch file from {$patchFile} ..."); system("patch -p0 < {$patchFile}"); } } // let's apply patch for libphp{php version}.so (apxs) if ($build->isEnabledVariant('apxs2')) { $apxs2Checker = new \PhpBrew\Tasks\Apxs2CheckTask($this->logger); $apxs2Checker->check($build); $apxs2Patch = new \PhpBrew\Tasks\Apxs2PatchTask($this->logger); $apxs2Patch->patch($build, $this->options); } foreach ($extra as $a) { $args[] = $a; } $cmd->args($args); $this->logger->info("===> Configuring {$build->version}..."); $cmd->append = false; $cmd->stdout = Config::getVersionBuildLogPath($build->name); echo "\n\n"; echo "Use tail command to see what's going on:\n"; echo " \$ tail -f {$cmd->stdout}\n\n\n"; $this->logger->debug($cmd->getCommand()); if ($this->options->nice) { $cmd->nice($this->options->nice); } $cmd->execute() !== false or die('Configure failed.'); // Then patch Makefile for PHP 5.3.x on 64bit system. $currentVersion = preg_replace('/[^\\d]*(\\d+).(\\d+).*/i', '$1.$2', $this->version); if (Utils::support64bit() && version_compare($currentVersion, '5.3', '==')) { $this->logger->info("===> Applying patch file for php5.3.x on 64bit machine."); system('sed -i \'/^BUILD_/ s/\\$(CC)/\\$(CXX)/g\' Makefile'); system('sed -i \'/EXTRA_LIBS = /s|$| -lstdc++|\' Makefile'); } }
/** * A test case for `neutral' virtual variant. */ public function testNeutralVirtualVariant() { $variants = new VariantBuilder(); $build = new Build('5.3.0'); // $build->setVersion('5.3.0'); $build->enableVariant('neutral'); $build->resolveVariants(); $options = $variants->build($build); // ignore `--with-libdir` because this option should be set depending on client environments. $actual = array_filter($options, function ($option) { return !preg_match("/^--with-libdir/", $option); }); $this->assertEquals(array(), $actual); }
/** * @param \PhpBrew\Build $build * @return bool */ public function check(Build $build) { $phpbin = $build->getBinDirectory() . DIRECTORY_SEPARATOR . 'php'; $dSYM = $build->getBinDirectory() . DIRECTORY_SEPARATOR . 'php.dSYM'; return !file_exists($phpbin) && file_exists($dSYM); }
/** * Build variants to configure options from php build object. * * @param Build $build The build object, contains version information * * @return array|void * @throws \Exception */ public function build(Build $build) { $customVirtualVariants = Config::getConfigParam('variants'); foreach (array_keys($build->getVariants()) as $variantName) { if (isset($customVirtualVariants[$variantName])) { foreach ($customVirtualVariants[$variantName] as $lib => $params) { if (is_array($params)) { $this->variants[$lib] = $params; } } } } // reset builtList $this->builtList = array(); // reset built options if ($build->hasVariant('all') || $build->hasVariant('neutral')) { $this->options = array(); } else { // build common options $this->options = array('--disable-all', '--enable-phar', '--enable-session', '--enable-short-tags', '--enable-tokenizer', '--with-pcre-regex'); if ($prefix = Utils::findIncludePrefix('zlib.h')) { $this->addOptions('--with-zlib=' . $prefix); } } if ($prefix = Utils::findLibPrefix('x86_64-linux-gnu')) { $this->addOptions("--with-libdir=lib/x86_64-linux-gnu"); } elseif ($prefix = Utils::findLibPrefix('i386-linux-gnu')) { $this->addOptions("--with-libdir=lib/i386-linux-gnu"); } // enable/expand virtual variants foreach ($this->virtualVariants as $name => $variantNames) { if ($build->isEnabledVariant($name)) { foreach ($variantNames as $subVariantName) { // enable the sub-variant only if it's not already enabled // in order to not override a non-default value with the default if (!$build->isEnabledVariant($subVariantName)) { $build->enableVariant($subVariantName); } } // it's a virtual variant, can not be built by buildVariant // method. $build->removeVariant($name); } } // Remove these enabled variant for disabled variants. $build->resolveVariants(); // before we build these options from variants, // we need to check the enabled and disabled variants $this->checkConflicts($build); foreach ($build->getVariants() as $feature => $userValue) { if ($options = $this->buildVariant($build, $feature, $userValue)) { $this->addOptions($options); } } foreach ($build->getDisabledVariants() as $feature => $true) { if ($options = $this->buildDisableVariant($build, $feature)) { $this->addOptions($options); } } /* $opts = array_merge( $opts , $this->getVersionSpecificOptions($version) ); */ $options = array_merge(array(), $this->options); // reset options $this->options = array(); return $options; }
public function run(Build $build, $variantOptions) { $extra = $build->getExtraOptions(); $prefix = $build->getInstallPrefix(); // append cflags if ($this->optimizationLevel) { $o = $this->optimizationLevel; $cflags = getenv('CFLAGS'); putenv("CFLAGS={$cflags} -O{$o}"); $_ENV['CFLAGS'] = "{$cflags} -O{$o}"; } $args = array(); if (!$this->options->{'no-config-cache'}) { // $args[] = "-C"; // project wise cache (--config-cache) $args[] = '--cache-file=' . escapeshellarg(Config::getCacheDir() . DIRECTORY_SEPARATOR . 'config.cache'); } $args[] = '--prefix=' . $prefix; if ($this->options->{'user-config'}) { $args[] = "--with-config-file-path={$prefix}/etc"; $args[] = "--with-config-file-scan-dir={$prefix}/var/db"; } else { $args[] = "--with-config-file-path={$prefix}/etc"; $args[] = "--with-config-file-scan-dir={$prefix}/var/db"; } if ($variantOptions) { $args = array_merge($args, $variantOptions); } $this->debug('Enabled variants: [' . implode(', ', array_keys($build->getVariants())) . ']'); $this->debug('Disabled variants: [' . implode(', ', array_keys($build->getDisabledVariants())) . ']'); // todo: move to pear variant $args[] = "--with-pear={$prefix}/lib/php"; // Options for specific versions // todo: extract to BuildPlan class: PHP53 BuildPlan, PHP54 BuildPlan, PHP55 BuildPlan ? if ($build->compareVersion('5.4') == -1) { // copied from https://github.com/Homebrew/homebrew-php/blob/master/Formula/php53.rb $args[] = '--enable-sqlite-utf8'; $args[] = '--enable-zend-multibyte'; } elseif ($build->compareVersion('5.6') == -1) { $args[] = '--enable-zend-signals'; } foreach ($extra as $a) { $args[] = $a; } $cmd = new CommandBuilder('./configure'); $cmd->args($args); $buildLogPath = $build->getBuildLogPath(); if (file_exists($buildLogPath)) { $newPath = $buildLogPath . '.' . filemtime($buildLogPath); $this->info("Found existing build.log, renaming it to {$newPath}"); rename($buildLogPath, $newPath); } $this->info("===> Configuring {$build->version}..."); $cmd->setAppendLog(true); $cmd->setLogPath($buildLogPath); $cmd->setStdout($this->options->{'stdout'}); if (!$this->options->{'stdout'}) { $this->logger->info("\n"); $this->logger->info("Use tail command to see what's going on:"); $this->logger->info(" \$ tail -F {$buildLogPath}\n\n"); } $this->debug($cmd->buildCommand()); if ($this->options->nice) { $cmd->nice($this->options->nice); } if (!$this->options->dryrun) { $code = $cmd->execute($lastline); if ($code !== 0) { throw new SystemCommandException("Configure failed: {$lastline}", $build, $buildLogPath); } } $build->setState(Build::STATE_CONFIGURE); }
public function execute($version) { if (!preg_match('/^php-/', $version)) { $version = 'php-' . $version; } $version = $this->getLatestMinorVersion($version, $this->options->old); $options = $this->options; $logger = $this->logger; // get options and variants for building php $args = func_get_args(); // the first argument is the target version. array_shift($args); $name = $this->options->name ?: $version; // find inherited variants $inheritedVariants = array(); if ($this->options->like) { $inheritedVariants = VariantParser::getInheritedVariants($this->options->like); } // ['extra_options'] => the extra options to be passed to ./configure command // ['enabled_variants'] => enabeld variants // ['disabled_variants'] => disabled variants $variantInfo = VariantParser::parseCommandArguments($args, $inheritedVariants); $info = PhpSource::getVersionInfo($version, $this->options->old); if (!$info) { throw new Exception("Version {$version} not found."); } $prepare = new PrepareDirectoryTask($this->logger); $prepare->prepareForVersion($version); // convert patch to realpath if ($this->options->patch) { $patchPaths = array(); foreach ($this->options->patch as $patch) { /** @var \SplFileInfo $patch */ $patchPath = realpath($patch); if ($patchPath !== false) { $patchPaths[(string) $patch] = $patchPath; } } // rewrite patch paths $this->options->keys['patch']->value = $patchPaths; } // Move to to build directory, because we are going to download distribution. $buildDir = Config::getBuildDir(); chdir($buildDir); $download = new DownloadTask($this->logger); $targetDir = $download->downloadByVersionString($version, $this->options->old, $this->options->force); if (!file_exists($targetDir)) { throw new Exception("Download failed."); } // Change directory to the downloaded source directory. chdir($targetDir); $buildPrefix = Config::getVersionBuildPrefix($version); if (!file_exists($buildPrefix)) { mkdir($buildPrefix, 0755, true); } // write variants info. $variantInfoFile = $buildPrefix . DIRECTORY_SEPARATOR . 'phpbrew.variants'; $this->logger->debug("Writing variant info to {$variantInfoFile}"); file_put_contents($variantInfoFile, serialize($variantInfo)); // The build object, contains the information to build php. $build = new Build($version, $name, $buildPrefix); $build->setInstallPrefix($buildPrefix); $build->setSourceDirectory($targetDir); $builder = new Builder($targetDir, $version); $builder->logger = $this->logger; $builder->options = $this->options; $this->logger->debug('Build Directory: ' . realpath($targetDir)); foreach ($variantInfo['enabled_variants'] as $name => $value) { $build->enableVariant($name, $value); } foreach ($variantInfo['disabled_variants'] as $name => $value) { $build->disableVariant($name); if ($build->hasVariant($name)) { $this->logger->warn("Removing variant {$name} since we've disabled it from command."); $build->removeVariant($name); } } $build->setExtraOptions($variantInfo['extra_options']); if ($options->clean) { $clean = new CleanTask($this->logger); $clean->cleanByVersion($version); } $buildLogFile = Config::getVersionBuildLogPath($version); $configure = new \PhpBrew\Tasks\ConfigureTask($this->logger); $configure->configure($build, $this->options); $buildTask = new BuildTask($this->logger); $buildTask->setLogPath($buildLogFile); $buildTask->build($build, $this->options); if ($options->{'test'}) { $test = new TestTask($this->logger); $test->setLogPath($buildLogFile); $test->test($build, $this->options); } $install = new InstallTask($this->logger); $install->setLogPath($buildLogFile); $install->install($build, $this->options); if ($options->{'post-clean'}) { $clean = new CleanTask($this->logger); $clean->cleanByVersion($version); } /** POST INSTALLATION **/ $dsym = new DSymTask($this->logger); $dsym->patch($build, $this->options); // copy php-fpm config $this->logger->info("---> Creating php-fpm.conf"); $phpFpmConfigPath = "sapi/fpm/php-fpm.conf"; $phpFpmTargetConfigPath = Config::getVersionEtcPath($version) . DIRECTORY_SEPARATOR . 'php-fpm.conf'; if (file_exists($phpFpmConfigPath)) { if (!file_exists($phpFpmTargetConfigPath)) { copy($phpFpmConfigPath, $phpFpmTargetConfigPath); } else { $this->logger->notice("Found existing {$phpFpmTargetConfigPath}."); } } $phpConfigPath = $options->production ? 'php.ini-production' : 'php.ini-development'; $this->logger->info("---> Copying {$phpConfigPath} "); if (file_exists($phpConfigPath)) { $targetConfigPath = Config::getVersionEtcPath($version) . DIRECTORY_SEPARATOR . 'php.ini'; if (file_exists($targetConfigPath)) { $this->logger->notice("Found existing {$targetConfigPath}."); } else { // TODO: Move this to PhpConfigPatchTask // move config file to target location copy($phpConfigPath, $targetConfigPath); // replace current timezone $timezone = ini_get('date.timezone'); $pharReadonly = ini_get('phar.readonly'); if ($timezone || $pharReadonly) { // patch default config $content = file_get_contents($targetConfigPath); if ($timezone) { $this->logger->info("---> Found date.timezone, patch config timezone with {$timezone}"); $content = preg_replace('/^date.timezone\\s*=\\s*.*/im', "date.timezone = {$timezone}", $content); } if (!$pharReadonly) { $this->logger->info("---> Disable phar.readonly option."); $content = preg_replace('/^phar.readonly\\s*=\\s*.*/im', "phar.readonly = 0", $content); } file_put_contents($targetConfigPath, $content); } } } $this->logger->info("Initializing pear config..."); $home = Config::getPhpbrewHome(); @mkdir("{$home}/tmp/pear/temp", 0755, true); @mkdir("{$home}/tmp/pear/cache_dir", 0755, true); @mkdir("{$home}/tmp/pear/download_dir", 0755, true); system("pear config-set temp_dir {$home}/tmp/pear/temp"); system("pear config-set cache_dir {$home}/tmp/pear/cache_dir"); system("pear config-set download_dir {$home}/tmp/pear/download_dir"); $this->logger->info("Enabling pear auto-discover..."); system("pear config-set auto_discover 1"); $this->logger->debug("Source directory: " . $targetDir); $this->logger->info("Congratulations! Now you have PHP with {$version}."); echo <<<EOT To use the newly built PHP, try the line(s) below: \$ phpbrew use {$version} Or you can use switch command to switch your default php version to {$version}: \$ phpbrew switch {$version} Enjoy! EOT; }
public function run(Build $build, $variantOptions) { $extra = $build->getExtraOptions(); if (!file_exists($build->getSourceDirectory() . DIRECTORY_SEPARATOR . 'configure')) { $this->debug("configure file not found, running buildconf script..."); $lastline = system('./buildconf', $status); if ($status !== 0) { throw new SystemCommandException("buildconf error: {$lastline}"); } } $prefix = $build->getInstallPrefix(); // append cflags if ($this->optimizationLevel) { $o = $this->optimizationLevel; $cflags = getenv('CFLAGS'); putenv("CFLAGS={$cflags} -O{$o}"); $_ENV['CFLAGS'] = "{$cflags} -O{$o}"; } $args = array(); $args[] = "--prefix=" . $prefix; $args[] = "--with-config-file-path={$prefix}/etc"; $args[] = "--with-config-file-scan-dir={$prefix}/var/db"; $args[] = "--with-pear={$prefix}/lib/php"; if ($variantOptions) { $args = array_merge($args, $variantOptions); } $this->debug('Enabled variants: ' . join(', ', array_keys($build->getVariants()))); $this->debug('Disabled variants: ' . join(', ', array_keys($build->getDisabledVariants()))); foreach ((array) $this->options->patch as $patchPath) { // copy patch file to here $this->info("===> Applying patch file from {$patchPath} ..."); // Search for strip parameter for ($i = 0; $i <= 16; $i++) { ob_start(); system("patch -p{$i} --dry-run < {$patchPath}", $return); ob_end_clean(); if ($return === 0) { system("patch -p{$i} < {$patchPath}"); break; } } } // let's apply patch for libphp{php version}.so (apxs) if ($build->isEnabledVariant('apxs2')) { $apxs2Checker = new \PhpBrew\Tasks\Apxs2CheckTask($this->logger); $apxs2Checker->check($build, $this->options); $apxs2Patch = new \PhpBrew\Tasks\Apxs2PatchTask($this->logger); $apxs2Patch->patch($build, $this->options); } foreach ($extra as $a) { $args[] = $a; } $cmd = new CommandBuilder('./configure'); $cmd->args($args); $buildLogPath = $build->getBuildLogPath(); if (file_exists($buildLogPath)) { $newPath = $buildLogPath . '.' . filemtime($buildLogPath); $this->info("Found existing build.log, renaming it to {$newPath}"); rename($buildLogPath, $newPath); } $this->info("===> Configuring {$build->version}..."); $cmd->setAppendLog(true); $cmd->setLogPath($buildLogPath); $cmd->setStdout($this->options->{'stdout'}); $this->logger->info("\n"); $this->logger->info("Use tail command to see what's going on:"); $this->logger->info(" \$ tail -F {$buildLogPath}\n\n"); $this->debug($cmd->getCommand()); if ($this->options->nice) { $cmd->nice($this->options->nice); } if (!$this->options->dryrun) { $code = $cmd->execute(); if ($code != 0) { throw new SystemCommandException("Configure failed: {$code}", $buildLogPath); } } if (!$this->options->{'no-patch'}) { $patch64bit = new \PhpBrew\Tasks\Patch64BitSupportTask($this->logger, $this->options); if ($patch64bit->match($build)) { $patch64bit->patch($build); } } $build->setState(Build::STATE_CONFIGURE); }
public function execute($version) { $distUrl = NULL; $versionInfo = array(); $releaseList = ReleaseList::getReadyInstance(); $versionDslParser = new VersionDslParser(); $clean = new MakeTask($this->logger, $this->options); $clean->setQuiet(); if ($root = $this->options->root) { Config::setPhpbrewRoot($root); } if ($home = $this->options->home) { Config::setPhpbrewHome($home); } if ('latest' === strtolower($version)) { $version = $releaseList->getLatestVersion(); } // this should point to master or the latest version branch yet to be released if ('next' === strtolower($version)) { $version = "github.com/php/php-src:master"; } if ($info = $versionDslParser->parse($version)) { $version = $info['version']; $distUrl = $info['url']; // always redownload when installing from github master // beware to keep this behavior after clean up the TODO below $this->options['force']->setValue(true); } else { // TODO ↓ clean later ↓ d.d.d versions should be part of the DSL too $version = preg_replace('/^php-/', '', $version); $versionInfo = $releaseList->getVersion($version); if (!$versionInfo) { throw new Exception("Version {$version} not found."); } $version = $versionInfo['version']; $distUrlPolicy = new DistributionUrlPolicy(); if ($this->options->mirror) { $distUrlPolicy->setMirrorSite($this->options->mirror); } $distUrl = $distUrlPolicy->buildUrl($version, $versionInfo['filename']); } // get options and variants for building php // and skip the first argument since it's the target version. $args = func_get_args(); array_shift($args); // shift the version name $semanticOptions = $this->parseSemanticOptions($args); $buildAs = isset($semanticOptions['as']) ? $semanticOptions['as'] : $this->options->name; $buildLike = isset($semanticOptions['like']) ? $semanticOptions['like'] : $this->options->like; // convert patch to realpath if ($this->options->patch) { $patchPaths = array(); foreach ($this->options->patch as $patch) { /** @var \SplFileInfo $patch */ $patchPath = realpath($patch); if ($patchPath !== false) { $patchPaths[(string) $patch] = $patchPath; } } // rewrite patch paths $this->options->keys['patch']->value = $patchPaths; } // Initialize the build object, contains the information to build php. $build = new Build($version, $buildAs); $installPrefix = Config::getInstallPrefix() . DIRECTORY_SEPARATOR . $build->getName(); if (!file_exists($installPrefix)) { mkdir($installPrefix, 0755, true); } $build->setInstallPrefix($installPrefix); // find inherited variants if ($buildLike) { if ($parentBuild = Build::findByName($buildLike)) { $build->loadVariantInfo($parentBuild->settings->toArray()); } } $msg = "===> phpbrew will now build {$build->getVersion()}"; if ($buildLike) { $msg .= ' using variants from ' . $buildLike; } if (isset($semanticOptions['using'])) { $msg .= ' plus custom variants: ' . join(', ', $semanticOptions['using']); $args = array_merge($args, $semanticOptions['using']); } if ($buildAs) { $msg .= ' as ' . $buildAs; } $this->logger->info($msg); if (!empty($args)) { $this->logger->debug("---> Parsing variants from command arguments '" . join(' ', $args) . "'"); } // ['extra_options'] => the extra options to be passed to ./configure command // ['enabled_variants'] => enabeld variants // ['disabled_variants'] => disabled variants $variantInfo = VariantParser::parseCommandArguments($args); $build->loadVariantInfo($variantInfo); // load again // assume +default variant if no build config is given and warn about that if (!$variantInfo['enabled_variants']) { $build->setBuildSettings(new DefaultBuildSettings()); $this->logger->notice("You haven't set any variant. A default set of extensions will be installed for the minimum requirement:"); $this->logger->notice('[' . implode(', ', array_keys($build->getVariants())) . ']'); $this->logger->notice("Please run 'phpbrew variants' for more information.\n"); } if (preg_match('/5\\.3\\./', $version)) { $this->logger->notice("PHP 5.3 requires +intl, enabled by default."); $build->enableVariant('intl'); } // always add +xml by default unless --without-pear is present // TODO: This can be done by "-pear" if (!in_array('--without-pear', $variantInfo['extra_options'])) { $build->enableVariant('xml'); } $this->logger->info('===> Loading and resolving variants...'); $removedVariants = $build->loadVariantInfo($variantInfo); if (!empty($removedVariants)) { $this->logger->debug('Removed variants: ' . join(',', $removedVariants)); } $prepareTask = new PrepareDirectoryTask($this->logger, $this->options); $prepareTask->run($build); // Move to to build directory, because we are going to download distribution. $buildDir = $this->options->{'build-dir'} ?: Config::getBuildDir(); if (!file_exists($buildDir)) { mkdir($buildDir, 0755, true); } $variantBuilder = new VariantBuilder(); $variants = $variantBuilder->build($build); $distFileDir = Config::getDistFileDir(); $downloadTask = new DownloadTask($this->logger, $this->options); $targetFilePath = $downloadTask->download($distUrl, $distFileDir, isset($versionInfo['md5']) ? $versionInfo['md5'] : NULL); if (!file_exists($targetFilePath)) { throw new Exception("Download failed, {$targetFilePath} does not exist."); } unset($downloadTask); $extractTask = new ExtractTask($this->logger, $this->options); $targetDir = $extractTask->extract($build, $targetFilePath, $buildDir); if (!file_exists($targetDir)) { throw new Exception("Extract failed, {$targetDir} does not exist."); } unset($extractTask); // Update build source directory $this->logger->debug('Source Directory: ' . realpath($targetDir)); $build->setSourceDirectory($targetDir); if (!$this->options->{'no-clean'} && file_exists($targetDir . DIRECTORY_SEPARATOR . 'Makefile')) { $this->logger->info("Found existing Makefile, running make clean to ensure everything will be rebuilt."); $this->logger->info("You can append --no-clean option after the install command if you don't want to rebuild."); $clean->clean($build); } // Change directory to the downloaded source directory. chdir($targetDir); // Write variants info. $variantInfoFile = $build->getInstallPrefix() . DIRECTORY_SEPARATOR . 'phpbrew.variants'; $this->logger->debug("Writing variant info to {$variantInfoFile}"); if (false === $build->writeVariantInfoFile($variantInfoFile)) { $this->logger->warn("Can't store variant info."); } $buildLogFile = $build->getBuildLogPath(); if (!$this->options->{'no-configure'}) { $configureTask = new ConfigureTask($this->logger, $this->options); $configureTask->run($build, $variants); unset($configureTask); // trigger __destruct } $buildTask = new BuildTask($this->logger, $this->options); $buildTask->run($build); unset($buildTask); // trigger __destruct if ($this->options->{'test'}) { $testTask = new TestTask($this->logger, $this->options); $testTask->run($build); unset($testTask); // trigger __destruct } if (!$this->options->{'no-install'}) { $installTask = new InstallTask($this->logger, $this->options); $installTask->install($build); unset($installTask); // trigger __destruct } if ($this->options->{'post-clean'}) { $clean->clean($build); } $dsym = new DSymTask($this->logger, $this->options); $dsym->patch($build, $this->options); // copy php-fpm config $this->logger->info("---> Creating php-fpm.conf"); $phpFpmConfigPath = "sapi/fpm/php-fpm.conf"; $phpFpmTargetConfigPath = $build->getEtcDirectory() . DIRECTORY_SEPARATOR . 'php-fpm.conf'; if (file_exists($phpFpmConfigPath)) { if (!file_exists($phpFpmTargetConfigPath)) { copy($phpFpmConfigPath, $phpFpmTargetConfigPath); } else { $this->logger->notice("Found existing {$phpFpmTargetConfigPath}."); } } $this->logger->info("---> Creating php.ini"); $phpConfigPath = $build->getSourceDirectory() . DIRECTORY_SEPARATOR . ($this->options->production ? 'php.ini-production' : 'php.ini-development'); $this->logger->info("---> Copying {$phpConfigPath} "); if (file_exists($phpConfigPath) && !$this->options->dryrun) { $targetConfigPath = $build->getEtcDirectory() . DIRECTORY_SEPARATOR . 'php.ini'; if (file_exists($targetConfigPath)) { $this->logger->notice("Found existing {$targetConfigPath}."); } else { // TODO: Move this to PhpConfigPatchTask // move config file to target location copy($phpConfigPath, $targetConfigPath); } if (!$this->options->{'no-patch'}) { $config = parse_ini_file($targetConfigPath, true); $configContent = file_get_contents($targetConfigPath); $patched = false; if (!isset($config['date']['timezone'])) { $this->logger->info('---> Found date.timezone is not set, patching...'); // Replace current timezone if ($timezone = ini_get('date.timezone')) { $this->logger->info("---> Found date.timezone, patching config timezone with {$timezone}"); $configContent = preg_replace('/^;?date.timezone\\s*=\\s*.*/im', "date.timezone = {$timezone}", $configContent); } $patched = true; } if (!isset($config['phar']['readonly'])) { $pharReadonly = ini_get('phar.readonly'); // 0 or "" means readonly is disabled manually if (!$pharReadonly) { $this->logger->info("---> Disabling phar.readonly option."); $configContent = preg_replace('/^;?phar.readonly\\s*=\\s*.*/im', "phar.readonly = 0", $configContent); } } file_put_contents($targetConfigPath, $configContent); } } $this->logger->info("Initializing pear config..."); $home = Config::getPhpbrewHome(); @mkdir("{$home}/tmp/pear/temp", 0755, true); @mkdir("{$home}/tmp/pear/cache_dir", 0755, true); @mkdir("{$home}/tmp/pear/download_dir", 0755, true); system("pear config-set temp_dir {$home}/tmp/pear/temp"); system("pear config-set cache_dir {$home}/tmp/pear/cache_dir"); system("pear config-set download_dir {$home}/tmp/pear/download_dir"); $this->logger->info("Enabling pear auto-discover..."); system("pear config-set auto_discover 1"); $this->logger->debug("Source directory: " . $targetDir); $buildName = $build->getName(); $this->logger->info("Congratulations! Now you have PHP with {$version} as {$buildName}"); echo <<<EOT To use the newly built PHP, try the line(s) below: \$ phpbrew use {$buildName} Or you can use switch command to switch your default php to {$buildName}: \$ phpbrew switch {$buildName} Enjoy! EOT; }
public function configure(Build $build, $options) { $root = Config::getPhpbrewRoot(); $buildDir = Config::getBuildDir(); $variantBuilder = new VariantBuilder(); $extra = $build->getExtraOptions(); if (!file_exists('configure')) { $this->debug("configure file not found, running buildconf script..."); system('./buildconf') !== false or die('buildconf error'); } $prefix = $build->getInstallPrefix(); // append cflags if ($this->optimizationLevel) { $o = $this->optimizationLevel; $cflags = getenv('CFLAGS'); putenv("CFLAGS={$cflags} -O{$o}"); $_ENV['CFLAGS'] = "{$cflags} -O{$o}"; } $args = array(); $args[] = "--prefix=" . $prefix; $args[] = "--with-config-file-path={$prefix}/etc"; $args[] = "--with-config-file-scan-dir={$prefix}/var/db"; $args[] = "--with-pear={$prefix}/lib/php"; $variantOptions = $variantBuilder->build($build); if ($variantOptions) { $args = array_merge($args, $variantOptions); } $this->debug('Enabled variants: ' . join(', ', array_keys($build->getVariants()))); $this->debug('Disabled variants: ' . join(', ', array_keys($build->getDisabledVariants()))); foreach ((array) $options->patch as $patchPath) { // copy patch file to here $this->info("===> Applying patch file from {$patchPath} ..."); // Search for strip parameter for ($i = 0; $i <= 16; $i++) { ob_start(); system("patch -p{$i} --dry-run < {$patchPath}", $return); ob_clean(); if ($return === 0) { system("patch -p{$i} < {$patchPath}"); break; } } } // let's apply patch for libphp{php version}.so (apxs) if ($build->isEnabledVariant('apxs2')) { $apxs2Checker = new \PhpBrew\Tasks\Apxs2CheckTask($this->logger); $apxs2Checker->check($build, $options); $apxs2Patch = new \PhpBrew\Tasks\Apxs2PatchTask($this->logger); $apxs2Patch->patch($build, $options); } foreach ($extra as $a) { $args[] = $a; } $cmd = new CommandBuilder('./configure'); $cmd->args($args); $this->info("===> Configuring {$build->version}..."); $cmd->append = false; $cmd->stdout = Config::getVersionBuildLogPath($build->name); echo "\n\n"; echo "Use tail command to see what's going on:\n"; echo " \$ tail -f {$cmd->stdout}\n\n\n"; $this->debug($cmd->getCommand()); if ($options->nice) { $cmd->nice($options->nice); } if (!$options->dryrun) { $cmd->execute() !== false or die('Configure failed.'); } $patch64bit = new \PhpBrew\Tasks\Patch64BitSupportTask($this->logger, $options); $patch64bit->patch($build, $options); }
public function __construct() { parent::__construct('5.3.29'); $this->setSourceDirectory(Config::getTempFileDir() . '/' . uniqid()); }