Merge branch 'bugfix/ini-writer-comments-at-line-end-4531'

fixes #4531
This commit is contained in:
Jannis Moßhammer 2013-08-14 15:05:21 +02:00
commit f8567058b4
3 changed files with 95 additions and 49 deletions

View File

@ -85,7 +85,7 @@ class IniEditor
*/ */
public function resetArrayElement(array $key, $section = null) public function resetArrayElement(array $key, $section = null)
{ {
$line = $this->getArrayEl($key, $section); $line = $this->getArrayElement($key, $section);
if ($line !== -1) { if ($line !== -1) {
$this->deleteLine($line); $this->deleteLine($line);
} }
@ -100,7 +100,7 @@ class IniEditor
*/ */
public function setArrayElement(array $key, $value, $section = null) public function setArrayElement(array $key, $value, $section = null)
{ {
$line = $this->getArrayEl($key,$section); $line = $this->getArrayElement($key,$section);
if ($line !== -1) { if ($line !== -1) {
if (isset($section)) { if (isset($section)) {
$this->updateLine($line,$this->formatKeyValuePair($key,$value)); $this->updateLine($line,$this->formatKeyValuePair($key,$value));
@ -125,7 +125,7 @@ class IniEditor
* *
* @return The line of the array element. * @return The line of the array element.
*/ */
private function getArrayEl(array $key, $section = null) private function getArrayElement(array $key, $section = null)
{ {
$line = isset($section) ? $this->getSectionLine($section) +1 : 0; $line = isset($section) ? $this->getSectionLine($section) +1 : 0;
$index = array_pop($key); $index = array_pop($key);
@ -135,16 +135,11 @@ class IniEditor
if ($this->isSectionDeclaration($l)) { if ($this->isSectionDeclaration($l)) {
return -1; return -1;
} }
if (strlen($formatted) > 0) { if (preg_match('/^\s*'.$formatted.'\[\]\s*=/',$l) === 1) {
if (preg_match('/^'.$formatted.'\[\]=/',$l) === 1 || return $line;
preg_match( }
'/^'.$formatted.$this->nestSeparator.$index.'=/',$l) === 1) { if ($this->isPropertyDeclaration($l,array_merge($key,array($index)))) {
return $line; return $line;
}
} else {
if (preg_match('/^'.$index.'=/',$l) === 1 ) {
return $line;
}
} }
} }
return -1; return -1;
@ -232,7 +227,7 @@ class IniEditor
private function cleanUpWhitespaces() private function cleanUpWhitespaces()
{ {
$i = count($this->text) - 1; $i = count($this->text) - 1;
for (; $i >= 0; $i--) { for (; $i > 0; $i--) {
$line = $this->text[$i]; $line = $this->text[$i];
if ($this->isSectionDeclaration($line)) { if ($this->isSectionDeclaration($line)) {
$i--; $i--;
@ -240,14 +235,14 @@ class IniEditor
/* /*
* Ignore comments that are glued to the section declaration * Ignore comments that are glued to the section declaration
*/ */
while ($i > 0 && preg_match('/^;/',$line) === 1) { while ($i > 0 && preg_match('/^\s*;/',$line) === 1) {
$i--; $i--;
$line = $this->text[$i]; $line = $this->text[$i];
} }
/* /*
* Remove whitespaces between the sections * Remove whitespaces between the sections
*/ */
while ($i > 0 && preg_match('/^[\s]*$/',$line) === 1) { while ($i > 0 && preg_match('/^\s*$/',$line) === 1) {
$this->deleteLine($i); $this->deleteLine($i);
$i--; $i--;
$line = $this->text[$i]; $line = $this->text[$i];
@ -281,7 +276,30 @@ class IniEditor
*/ */
private function updateLine($lineNr, $content) private function updateLine($lineNr, $content)
{ {
$this->text[$lineNr] = $content; $comment = $this->getComment($this->text[$lineNr]);
if (strlen($comment) > 0) {
$comment = " ; " . trim($comment);
}
$this->text[$lineNr] = str_pad($content,43) . $comment;
}
/**
* Get the comment from the given line
*
* @param $lineContent The content of the line
*
* @return string The extracted comment
*/
private function getComment($lineContent)
{
/*
* Remove all content in double quotes that is not behind a semicolon, recognizing
* escaped double quotes inside the string
*/
$cleaned = preg_replace('/^[^;"]*"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"/s','',$lineContent);
$matches = mb_split(';',$cleaned,2);
return array_key_exists(1,$matches) ? $matches[1] : "";
} }
/** /**
@ -304,7 +322,7 @@ class IniEditor
*/ */
private function formatKeyValuePair(array $key, $value) private function formatKeyValuePair(array $key, $value)
{ {
return $this->formatKey($key).'='.$this->formatValue($value); return str_pad($this->formatKey($key),19) . " = ".$this->formatValue($value);
} }
/** /**
@ -327,7 +345,7 @@ class IniEditor
$i = 0; $i = 0;
$started = isset($section) ? false: true; $started = isset($section) ? false: true;
foreach ($this->text as $line) { foreach ($this->text as $line) {
if ($started && preg_match('/^\[/',$line) === 1) { if ($started && $this->isSectionDeclaration($line)) {
if ($i === 0) { if ($i === 0) {
return $i; return $i;
} }
@ -335,11 +353,11 @@ class IniEditor
* ignore all comments 'glued' to the next section, to allow section * ignore all comments 'glued' to the next section, to allow section
* comments in front of sections * comments in front of sections
*/ */
while (preg_match('/^;/',$this->text[$i - 1]) === 1) { while ($i > 0 && preg_match('/^\s*;/',$this->text[$i - 1]) === 1) {
$i--; $i--;
} }
return $i; return $i;
} elseif (preg_match('/^\['.$section.'.*\]/',$line) === 1) { } elseif ( $this->isSectionDeclaration($line,$section) ) {
$started = true; $started = true;
} }
$i++; $i++;
@ -350,17 +368,37 @@ class IniEditor
return $i; return $i;
} }
/**
* Check if the line contains the property declaration for a key
*
* @param $lineContent The content of the line
* @param array $key The key this declaration is supposed to have
*
* @return boolean True, when the lineContent is a property declaration
*/
private function isPropertyDeclaration($lineContent, array $key)
{
return preg_match(
'/^\s*' . $this->formatKey($key) .'\s*=\s*/'
,$lineContent
) === 1;
}
/** /**
* Check if the given line contains a section declaration * Check if the given line contains a section declaration
* *
* @param $lineContent The content of the line * @param $lineContent The content of the line
* @param string $section The optional section name that will be assumed * @param string $section The optional section name that will be assumed
* *
* @return bool * @return bool True, when the lineContent is a section declaration
*/ */
private function isSectionDeclaration($lineContent, $section = "") private function isSectionDeclaration($lineContent, $section = null)
{ {
return preg_match('/^\[/'.$section,$lineContent) === 1; if (isset($section)) {
return preg_match('/^\s*\[\s*'.$section.'\s*[\]:]/',$lineContent) === 1;
} else {
return preg_match('/^\s*\[/',$lineContent) === 1;
}
} }
/** /**
@ -374,7 +412,7 @@ class IniEditor
{ {
$i = 0; $i = 0;
foreach ($this->text as $line) { foreach ($this->text as $line) {
if (preg_match('/^\['.$section.'/',$line)) { if ($this->isSectionDeclaration($line,$section)) {
return $i; return $i;
} }
$i++; $i++;
@ -388,7 +426,7 @@ class IniEditor
* @param array $keys The key and its parents * @param array $keys The key and its parents
* @param $section The section of the key * @param $section The section of the key
* *
* @return int The line number * @return int The line number
*/ */
private function getKeyLine(array $keys, $section = null) private function getKeyLine(array $keys, $section = null)
{ {
@ -396,13 +434,13 @@ class IniEditor
$inSection = isset($section) ? false : true; $inSection = isset($section) ? false : true;
$i = 0; $i = 0;
foreach ($this->text as $line) { foreach ($this->text as $line) {
if ($inSection && preg_match('/^\[/',$line) === 1) { if ($inSection && $this->isSectionDeclaration($line)) {
return -1; return -1;
} }
if ($inSection && preg_match('/^'.$key.'=/',$line) === 1) { if ($inSection && $this->isPropertyDeclaration($line,$keys)) {
return $i; return $i;
} }
if (!$inSection && preg_match('/^\[ *'.$section.' *[\]:]/',$line) === 1) { if (!$inSection && $this->isSectionDeclaration($line,$section)) {
$inSection = true; $inSection = true;
} }
$i++; $i++;
@ -448,7 +486,7 @@ class IniEditor
} }
/** /**
* Prepare a value for INI * Prepare a value for INe
* *
* @param $value The value of the string * @param $value The value of the string
* *
@ -465,7 +503,7 @@ class IniEditor
} elseif (strpos($value, '"') === false) { } elseif (strpos($value, '"') === false) {
return '"' . $value . '"'; return '"' . $value . '"';
} else { } else {
throw new ConfigurationError('Value can not contain double quotes "'); return '"' . str_replace('"','\"',$value) . '"';
} }
} }
} }

View File

@ -54,10 +54,10 @@ class PreservingIniWriter extends \Zend_Config_Writer_FileAbstract
/** /**
* Create a property diff and apply the changes to the editor * Create a property diff and apply the changes to the editor
* *
* @param Zend_Config $oldconfig The config representing the state before the change * @param Zend_Config $oldconfig The config representing the state before the change
* @param Zend_Config $newconfig The config representing the state after the change * @param Zend_Config $newconfig The config representing the state after the change
* @param IniEditor $eeditor The editor that should be used to edit the old config file * @param IniEditor $editor The editor that should be used to edit the old config file
* @param array $parents The parent keys that should be respected when editing the config * @param array $parents The parent keys that should be respected when editing the config
*/ */
private function diffConfigs( private function diffConfigs(
Zend_Config $oldconfig, Zend_Config $oldconfig,
@ -72,10 +72,10 @@ class PreservingIniWriter extends \Zend_Config_Writer_FileAbstract
/** /**
* Search for created and updated properties and use the editor to create or update these entries * Search for created and updated properties and use the editor to create or update these entries
* *
* @param Zend_Config $oldconfig The config representing the state before the change * @param Zend_Config $oldconfig The config representing the state before the change
* @param Zend_Config $newconfig The config representing the state after the change * @param Zend_Config $newconfig The config representing the state after the change
* @param IniEditor $eeditor The editor that should be used to edit the old config file * @param IniEditor $editor The editor that should be used to edit the old config file
* @param array $parents The parent keys that should be respected when editing the config * @param array $parents The parent keys that should be respected when editing the config
*/ */
private function diffPropertyUpdates( private function diffPropertyUpdates(
Zend_Config $oldconfig, Zend_Config $oldconfig,
@ -131,10 +131,10 @@ class PreservingIniWriter extends \Zend_Config_Writer_FileAbstract
/** /**
* Search for deleted properties and use the editor to delete these entries * Search for deleted properties and use the editor to delete these entries
* *
* @param Zend_Config $oldconfig The config representing the state before the change * @param Zend_Config $oldconfig The config representing the state before the change
* @param Zend_Config $newconfig The config representing the state after the change * @param Zend_Config $newconfig The config representing the state after the change
* @param IniEditor $eeditor The editor that should be used to edit the old config file * @param IniEditor $editor The editor that should be used to edit the old config file
* @param array $parents The parent keys that should be respected when editing the config * @param array $parents The parent keys that should be respected when editing the config
*/ */
private function diffPropertyDeletions( private function diffPropertyDeletions(
Zend_Config $oldconfig, Zend_Config $oldconfig,

View File

@ -27,7 +27,6 @@
*/ */
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
namespace Tests\Icinga\PreservingIniWriterTest; namespace Tests\Icinga\PreservingIniWriterTest;
require_once 'Zend/Config.php'; require_once 'Zend/Config.php';
@ -48,16 +47,23 @@ class PreservingIniWriterTest extends \PHPUnit_Framework_TestCase {
public function setUp() public function setUp()
{ {
$ini = $ini =
';1 '
trailing1="wert" trailing1="wert"
arr[]="0" arr[]="0"
arr[]="1" arr[]="1"
arr[]="2" arr[]="2"
arr[]="3" arr[]="3"
Trailing2=
;1
;2 ;2
;3 ;3
Trailing2= [section]
property = "some value" ; Some " ; comment"
property2 = "some ;value" ; Some comment with " quotes "
property3.nest1.nest2 = "value" ; ;
[parent] [parent]
;4 ;4
;5 ;5
@ -82,8 +88,6 @@ PropOne="overwritten"
'; ';
$this->writeToTmp('orig',$ini); $this->writeToTmp('orig',$ini);
$this->writeToTmp('sonst','');
$emptyIni = " "; $emptyIni = " ";
$this->writeToTmp('empty',$emptyIni); $this->writeToTmp('empty',$emptyIni);
@ -262,7 +266,7 @@ prop2="5"
'Section array changed.'); 'Section array changed.');
$this->assertEquals('changed',$config->parent->many->many->nests, $this->assertEquals('changed',$config->parent->many->many->nests,
'Change strongy nested value.'); 'Change strongly nested value.');
$this->assertEquals('new',$config->parent->many->many->new, $this->assertEquals('new',$config->parent->many->many->new,
'Ccreate strongy nested value.'); 'Ccreate strongy nested value.');
@ -297,6 +301,10 @@ prop2="5"
$config->arr->{2} = "update"; $config->arr->{2} = "update";
$config->arr->{4} = "arrvalue"; $config->arr->{4} = "arrvalue";
$config->section->property = "updated";
unset($config->section->property3);
$config->section->property4 = "created";
$config->parent->propOne = null; $config->parent->propOne = null;
$config->parent->propThree = 'update'; $config->parent->propThree = 'update';
$config->parent->new = 1; $config->parent->new = 1;