Commit 7fa8e6c1 authored by Michael McAndrew's avatar Michael McAndrew

upgrading composer for more useful error messages

parent 44cc680b
......@@ -13,7 +13,7 @@ echo '> PHP is using the following php.ini file:'.PHP_EOL;
if ($iniPath) {
echo_style('green', ' '.$iniPath);
} else {
echo_style('warning', ' WARNING: No configuration file (php.ini) used by PHP!');
echo_style('yellow', ' WARNING: No configuration file (php.ini) used by PHP!');
}
echo PHP_EOL.PHP_EOL;
......@@ -22,7 +22,6 @@ echo '> Checking Symfony requirements:'.PHP_EOL.' ';
$messages = array();
foreach ($symfonyRequirements->getRequirements() as $req) {
/** @var $req Requirement */
if ($helpText = get_error_message($req, $lineSize)) {
echo_style('red', 'E');
$messages['error'][] = $helpText;
......@@ -121,10 +120,14 @@ function echo_block($style, $title, $message)
echo PHP_EOL.PHP_EOL;
echo_style($style, str_repeat(' ', $width).PHP_EOL);
echo_style($style, str_pad(' ['.$title.']', $width, ' ', STR_PAD_RIGHT).PHP_EOL);
echo_style($style, str_pad($message, $width, ' ', STR_PAD_RIGHT).PHP_EOL);
echo_style($style, str_repeat(' ', $width).PHP_EOL);
echo_style($style, str_repeat(' ', $width));
echo PHP_EOL;
echo_style($style, str_pad(' ['.$title.']', $width, ' ', STR_PAD_RIGHT));
echo PHP_EOL;
echo_style($style, $message);
echo PHP_EOL;
echo_style($style, str_repeat(' ', $width));
echo PHP_EOL;
}
function has_color_support()
......
This diff is collapsed.
......@@ -9,11 +9,11 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\HttpFoundation\RequestStack;
class Publisher{
public $bookConfigFile;
public $messages;
public function __construct(RequestStack $requestStack, $logger, $fs, $configDir, $reposRoot, $publishRoot){
$this->configDir = $configDir;
$this->reposRoot = $reposRoot;
......@@ -22,31 +22,31 @@ class Publisher{
$this->logger = $logger;
$this->fs = $fs;
}
public function Publish($book, $lang, $branch)
{
$this->book = $book;
$this->lang = $lang;
$this->branch = $branch;
//Attempt to load a configuration file for the book
//Attempt to load a configuration file for the book
$bookConfigFile = $this->configDir."/{$book}.yml";
if (!$this->fs->exists($bookConfigFile)) {
$this->addMessage('CRITICAL', "Could not find config file ({$bookConfigFile}) for book '{$book}'.", 'd');
return;
}
$this->addMessage('INFO', "Loaded config file ({$bookConfigFile}) for '{$book}' documentation.");
$this->addMessage('NOTICE', "Publishing '{$book}' documentation...");
$yaml = new Parser();
$bookConfig = $yaml->parse(file_get_contents("$bookConfigFile"));
//Check that the requested publishing language exists in the book config.
if (!isset($bookConfig['langs'][$lang])) {
$this->addMessage('CRITICAL', "Language '{$lang}' is not defined in config file ({$bookConfigFile}).");
return;
}
$bookRepo = "$this->reposRoot/{$book}/{$lang}";
//See if the repo has already been cloned, and if not, clone it
if (!$this->fs->exists($bookRepo.'/.git')) {
......@@ -60,9 +60,9 @@ class Publisher{
}
}else{
$this->addMessage('INFO', "Repository exists at '{$bookRepo}'.");
}
//If we are on the not on the correct branch, attempt to check it out (first locally, then remotely).
$gitCheckCurrentBranch = new Process('git rev-parse --abbrev-ref HEAD', $bookRepo);
$gitCheckCurrentBranch->run();
......@@ -87,27 +87,32 @@ class Publisher{
$gitCheckoutBranch->run();
}
$this->addMessage('INFO', "On '{$branch}' branch.");
$this->addMessage('INFO', "Running 'git pull' to update '{$branch}' branch.");
$gitPull = new Process('git pull', $bookRepo);
$gitPull->run();
//Override some settings from the yml before publishing
$mkdocsConfig = $yaml->parse(file_get_contents("{$bookRepo}/mkdocs.yml"));
try{
$mkdocsConfig = $yaml->parse(file_get_contents("{$bookRepo}/mkdocs.yml"));
} catch (\Exception $e){
$this->addMessage('CRITICAL', "Error processing yaml: {$e->getMessage()}");
return;
}
//@TODO create a CiviCRM theme so that we can uncomment this line
//$mkdocsConfig['theme']="bootstrap";
//$mkdocsConfig['theme_dir']=$k->getRootDir().'/mkdocsthemes/civicrm';
$mkDocsBuildFileDir = $this->reposRoot.'/buildfiles';
if (!$this->fs->exists($mkDocsBuildFileDir)) {
$this->fs->mkdir($mkDocsBuildFileDir);
}
$buildConfigFile = $mkDocsBuildFileDir."/{$book}.{$lang}.{$branch}.yml";
$dumper = new Dumper();
file_put_contents($buildConfigFile, $dumper->dump($mkdocsConfig, 2));
$publishDir = $this->publishRoot."/{$book}/{$lang}/{$branch}";
$buildCommand = "mkdocs build -c -f {$buildConfigFile} -d {$publishDir}";
$this->addMessage('NOTICE', "Running '{$buildCommand}'");
......@@ -118,7 +123,7 @@ class Publisher{
//echo nl2br($mkdocs->getOutput()); (don't think anything gets outputed by this command)
$mkdocsLogMessages = explode("\n", trim($mkdocs->getErrorOutput()));
$this->addMessage('INFO', "mkdocs output: '{$mkdocs->getErrorOutput()}'");
// var_dump($mkdocsLogMessages);
foreach ($mkdocsLogMessages as $mkdocsLogMessage) {
//var_dump($mkdocsLogMessage);
......@@ -126,20 +131,20 @@ class Publisher{
$mkdocsErrors = true;
}
}
$bookUrl = "/{$book}/{$lang}/{$branch}";
if ($mkdocsErrors) {
$this->addMessage('CRITICAL', "Book published with errors (see above for details) at <a href='{$this->baseUrl}$bookUrl'>{$this->baseUrl}$bookUrl</a>.");
} else {
$this->addMessage('NOTICE', "Book published successfully at <a href='{$this->baseUrl}$bookUrl'>{$this->baseUrl}$bookUrl</a>.");
}
//check and update symlinks so that latest and stable point to the right places
$symlinks = array('latest', 'stable');
$langDir = realpath("$publishDir/..");
//@TODO break this out into its own function that can also be called at a certain URL.
foreach($symlinks as $symlink){
if ($this->fs->exists("$langDir/$symlink")) {
......@@ -158,7 +163,7 @@ class Publisher{
}
return 1;
}
protected function addMessage($label, $content)
{
$this->messages[] = array('label' => $label, 'content' => $content);
......
......@@ -168,6 +168,9 @@ class PhpIniRequirement extends Requirement
*/
class RequirementCollection implements IteratorAggregate
{
/**
* @var Requirement[]
*/
private $requirements = array();
/**
......@@ -265,7 +268,7 @@ class RequirementCollection implements IteratorAggregate
/**
* Returns both requirements and recommendations.
*
* @return array Array of Requirement instances
* @return Requirement[]
*/
public function all()
{
......@@ -275,7 +278,7 @@ class RequirementCollection implements IteratorAggregate
/**
* Returns all mandatory requirements.
*
* @return array Array of Requirement instances
* @return Requirement[]
*/
public function getRequirements()
{
......@@ -292,7 +295,7 @@ class RequirementCollection implements IteratorAggregate
/**
* Returns the mandatory requirements that were not met.
*
* @return array Array of Requirement instances
* @return Requirement[]
*/
public function getFailedRequirements()
{
......@@ -309,7 +312,7 @@ class RequirementCollection implements IteratorAggregate
/**
* Returns all optional recommendations.
*
* @return array Array of Requirement instances
* @return Requirement[]
*/
public function getRecommendations()
{
......@@ -326,7 +329,7 @@ class RequirementCollection implements IteratorAggregate
/**
* Returns the recommendations that were not met.
*
* @return array Array of Requirement instances
* @return Requirement[]
*/
public function getFailedRecommendations()
{
......@@ -376,7 +379,8 @@ class RequirementCollection implements IteratorAggregate
*/
class SymfonyRequirements extends RequirementCollection
{
const REQUIRED_PHP_VERSION = '5.3.3';
const LEGACY_REQUIRED_PHP_VERSION = '5.3.3';
const REQUIRED_PHP_VERSION = '5.5.9';
/**
* Constructor that initializes the requirements.
......@@ -386,16 +390,26 @@ class SymfonyRequirements extends RequirementCollection
/* mandatory requirements follow */
$installedPhpVersion = phpversion();
$requiredPhpVersion = $this->getPhpRequiredVersion();
$this->addRequirement(
version_compare($installedPhpVersion, self::REQUIRED_PHP_VERSION, '>='),
sprintf('PHP version must be at least %s (%s installed)', self::REQUIRED_PHP_VERSION, $installedPhpVersion),
sprintf('You are running PHP version "<strong>%s</strong>", but Symfony needs at least PHP "<strong>%s</strong>" to run.
Before using Symfony, upgrade your PHP installation, preferably to the latest version.',
$installedPhpVersion, self::REQUIRED_PHP_VERSION),
sprintf('Install PHP %s or newer (installed version is %s)', self::REQUIRED_PHP_VERSION, $installedPhpVersion)
$this->addRecommendation(
$requiredPhpVersion,
'Vendors should be installed in order to check all requirements.',
'Run the <code>composer install</code> command.',
'Run the "composer install" command.'
);
if (false !== $requiredPhpVersion) {
$this->addRequirement(
version_compare($installedPhpVersion, $requiredPhpVersion, '>='),
sprintf('PHP version must be at least %s (%s installed)', $requiredPhpVersion, $installedPhpVersion),
sprintf('You are running PHP version "<strong>%s</strong>", but Symfony needs at least PHP "<strong>%s</strong>" to run.
Before using Symfony, upgrade your PHP installation, preferably to the latest version.',
$installedPhpVersion, $requiredPhpVersion),
sprintf('Install PHP %s or newer (installed version is %s)', $requiredPhpVersion, $installedPhpVersion)
);
}
$this->addRequirement(
version_compare($installedPhpVersion, '5.3.16', '!='),
'PHP version must not be 5.3.16 as Symfony won\'t work properly with it',
......@@ -425,13 +439,15 @@ class SymfonyRequirements extends RequirementCollection
'Change the permissions of either "<strong>app/logs/</strong>" or "<strong>var/logs/</strong>" directory so that the web server can write into it.'
);
$this->addPhpIniRequirement(
'date.timezone', true, false,
'date.timezone setting must be set',
'Set the "<strong>date.timezone</strong>" setting in php.ini<a href="#phpini">*</a> (like Europe/Paris).'
);
if (version_compare($installedPhpVersion, '7.0.0', '<')) {
$this->addPhpIniRequirement(
'date.timezone', true, false,
'date.timezone setting must be set',
'Set the "<strong>date.timezone</strong>" setting in php.ini<a href="#phpini">*</a> (like Europe/Paris).'
);
}
if (version_compare($installedPhpVersion, self::REQUIRED_PHP_VERSION, '>=')) {
if (false !== $requiredPhpVersion && version_compare($installedPhpVersion, $requiredPhpVersion, '>=')) {
$timezones = array();
foreach (DateTimeZone::listAbbreviations() as $abbreviations) {
foreach ($abbreviations as $abbreviation) {
......@@ -677,6 +693,21 @@ class SymfonyRequirements extends RequirementCollection
'Upgrade your <strong>intl</strong> extension with a newer ICU version (4+).'
);
if (class_exists('Symfony\Component\Intl\Intl')) {
$this->addRecommendation(
\Symfony\Component\Intl\Intl::getIcuDataVersion() <= \Symfony\Component\Intl\Intl::getIcuVersion(),
sprintf('intl ICU version installed on your system is outdated (%s) and does not match the ICU data bundled with Symfony (%s)', \Symfony\Component\Intl\Intl::getIcuVersion(), \Symfony\Component\Intl\Intl::getIcuDataVersion()),
'To get the latest internationalization data upgrade the ICU system package and the intl PHP extension.'
);
if (\Symfony\Component\Intl\Intl::getIcuDataVersion() <= \Symfony\Component\Intl\Intl::getIcuVersion()) {
$this->addRecommendation(
\Symfony\Component\Intl\Intl::getIcuDataVersion() === \Symfony\Component\Intl\Intl::getIcuVersion(),
sprintf('intl ICU version installed on your system (%s) does not match the ICU data bundled with Symfony (%s)', \Symfony\Component\Intl\Intl::getIcuVersion(), \Symfony\Component\Intl\Intl::getIcuDataVersion()),
'To avoid internationalization data inconsistencies upgrade the symfony/intl component.'
);
}
}
$this->addPhpIniRecommendation(
'intl.error_level',
create_function('$cfgValue', 'return (int) $cfgValue === 0;'),
......@@ -708,9 +739,9 @@ class SymfonyRequirements extends RequirementCollection
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$this->addRecommendation(
$this->getRealpathCacheSize() > 1000,
'realpath_cache_size should be above 1024 in php.ini',
'Set "<strong>realpath_cache_size</strong>" to e.g. "<strong>1024</strong>" in php.ini<a href="#phpini">*</a> to improve performance on windows.'
$this->getRealpathCacheSize() >= 5 * 1024 * 1024,
'realpath_cache_size should be at least 5M in php.ini',
'Setting "<strong>realpath_cache_size</strong>" to e.g. "<strong>5242880</strong>" or "<strong>5M</strong>" in php.ini<a href="#phpini">*</a> may improve performance on Windows significantly in some cases.'
);
}
......@@ -749,7 +780,11 @@ class SymfonyRequirements extends RequirementCollection
{
$size = ini_get('realpath_cache_size');
$size = trim($size);
$unit = strtolower(substr($size, -1, 1));
$unit = '';
if (!ctype_digit($size)) {
$unit = strtolower(substr($size, -1, 1));
$size = (int) substr($size, 0, -1);
}
switch ($unit) {
case 'g':
return $size * 1024 * 1024 * 1024;
......@@ -761,4 +796,28 @@ class SymfonyRequirements extends RequirementCollection
return (int) $size;
}
}
/**
* Defines PHP required version from Symfony version.
*
* @return string|false The PHP required version or false if it could not be guessed
*/
protected function getPhpRequiredVersion()
{
if (!file_exists($path = __DIR__.'/../composer.lock')) {
return false;
}
$composerLock = json_decode(file_get_contents($path), true);
foreach ($composerLock['packages'] as $package) {
$name = $package['name'];
if ('symfony/symfony' !== $name && 'symfony/http-kernel' !== $name) {
continue;
}
return (int) $package['version'][1] > 2 ? self::REQUIRED_PHP_VERSION : self::LEGACY_REQUIRED_PHP_VERSION;
}
return false;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment