diff --git a/CHANGELOG.md b/CHANGELOG.md index 93d48cad4..88d1c8151 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +### [1.0.2] - 2016-04-21 + + * Fixed regression in 1.0.1 on systems with mbstring.func_overload enabled + * Fixed regression in 1.0.1 that made dev packages update to the latest reference even if not whitelisted in a partial update + * Fixed init command ignoring the COMPOSER env var for choosing the json file name + * Fixed error reporting bug when the dependency resolution fails + * Fixed handling of `$` sign in composer config command in some cases it could corrupt the json file + ### [1.0.1] - 2016-04-18 * Fixed URL updating when a package's URL changes, composer.lock now contains the right URL including correct reference @@ -335,6 +343,7 @@ * Initial release +[1.0.2]: https://github.com/composer/composer/compare/1.0.2...1.0.2 [1.0.1]: https://github.com/composer/composer/compare/1.0.0...1.0.1 [1.0.0]: https://github.com/composer/composer/compare/1.0.0-beta2...1.0.0 [1.0.0-beta2]: https://github.com/composer/composer/compare/1.0.0-beta1...1.0.0-beta2 diff --git a/src/Composer/Json/JsonManipulator.php b/src/Composer/Json/JsonManipulator.php index ca0281c29..2611e536d 100644 --- a/src/Composer/Json/JsonManipulator.php +++ b/src/Composer/Json/JsonManipulator.php @@ -74,14 +74,16 @@ class JsonManipulator if (isset($decoded[$type][$package])) { // update existing link $packageRegex = str_replace('/', '\\\\?/', preg_quote($package)); - // addcslashes is used to double up backslashes since preg_replace resolves them as back references otherwise, see #1588 - $links = preg_replace('{"'.$packageRegex.'"(\s*:\s*)'.self::$JSON_STRING.'}i', addcslashes(JsonFile::encode($package).'${1}"'.$constraint.'"', '\\'), $links); + $links = preg_replace_callback('{"'.$packageRegex.'"(\s*:\s*)'.self::$JSON_STRING.'}i', function ($m) use ($package, $constraint) { + return JsonFile::encode($package) . $m[1] . '"' . $constraint . '"'; + }, $links); } else { if ($this->pregMatch('#^\s*\{\s*\S+.*?(\s*\}\s*)$#s', $links, $match)) { // link missing but non empty links $links = preg_replace( '{'.preg_quote($match[1]).'$}', - addcslashes(',' . $this->newline . $this->indent . $this->indent . JsonFile::encode($package).': '.JsonFile::encode($constraint) . $match[1], '\\'), + // addcslashes is used to double up backslashes/$ since preg_replace resolves them as back references otherwise, see #1588 + addcslashes(',' . $this->newline . $this->indent . $this->indent . JsonFile::encode($package).': '.JsonFile::encode($constraint) . $match[1], '\\$'), $links ); } else { @@ -223,7 +225,7 @@ class JsonManipulator // child missing but non empty children $children = preg_replace( '#'.$match[1].'$#', - addcslashes(',' . $this->newline . $this->indent . $this->indent . JsonFile::encode($name).': '.$this->format($value, 1) . $match[1], '\\'), + addcslashes(',' . $this->newline . $this->indent . $this->indent . JsonFile::encode($name).': '.$this->format($value, 1) . $match[1], '\\$'), $children ); } else { @@ -235,7 +237,9 @@ class JsonManipulator $children = $this->newline . $this->indent . $this->indent . JsonFile::encode($name).': '.$this->format($value, 1) . $children; } - $this->contents = preg_replace($nodeRegex, addcslashes('${1}${2}'.$children.'${4}${5}', '\\'), $this->contents); + $this->contents = preg_replace_callback($nodeRegex, function ($m) use ($children) { + return $m[1] . $m[2] . $children . $m[4] . $m[5]; + }, $this->contents); return true; } @@ -353,7 +357,7 @@ class JsonManipulator if ($this->pregMatch('#[^{\s](\s*)\}$#', $this->contents, $match)) { $this->contents = preg_replace( '#'.$match[1].'\}$#', - addcslashes(',' . $this->newline . $this->indent . JsonFile::encode($key). ': '. $content . $this->newline . '}', '\\'), + addcslashes(',' . $this->newline . $this->indent . JsonFile::encode($key). ': '. $content . $this->newline . '}', '\\$'), $this->contents ); @@ -363,7 +367,7 @@ class JsonManipulator // append at the end of the file $this->contents = preg_replace( '#\}$#', - addcslashes($this->indent . JsonFile::encode($key). ': '.$content . $this->newline . '}', '\\'), + addcslashes($this->indent . JsonFile::encode($key). ': '.$content . $this->newline . '}', '\\$'), $this->contents ); diff --git a/src/Composer/Repository/Vcs/GitDriver.php b/src/Composer/Repository/Vcs/GitDriver.php index e9730412d..e98858abc 100644 --- a/src/Composer/Repository/Vcs/GitDriver.php +++ b/src/Composer/Repository/Vcs/GitDriver.php @@ -38,6 +38,7 @@ class GitDriver extends VcsDriver public function initialize() { if (Filesystem::isLocalPath($this->url)) { + $this->url = preg_replace('{[\\/]\.git/?$}', '', $this->url); $this->repoDir = $this->url; $cacheUrl = realpath($this->url); } else { @@ -219,7 +220,7 @@ class GitDriver extends VcsDriver */ public static function supports(IOInterface $io, Config $config, $url, $deep = false) { - if (preg_match('#(^git://|\.git$|git(?:olite)?@|//git\.|//github.com/)#i', $url)) { + if (preg_match('#(^git://|\.git/?$|git(?:olite)?@|//git\.|//github.com/)#i', $url)) { return true; } diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index e51b74105..847f8d8ee 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -476,13 +476,13 @@ class Filesystem */ public static function isLocalPath($path) { - return (bool) preg_match('{^(file://|/|[a-z]:[\\\\/]|\.\.[\\\\/]|[a-z0-9_.-]+[\\\\/])}i', $path); + return (bool) preg_match('{^(file://|/|/?[a-z]:[\\\\/]|\.\.[\\\\/]|[a-z0-9_.-]+[\\\\/])}i', $path); } public static function getPlatformPath($path) { if (Platform::isWindows()) { - $path = preg_replace('{^(?:file:///([a-z])/)}i', 'file://$1:/', $path); + $path = preg_replace('{^(?:file:///([a-z]):?/)}i', 'file://$1:/', $path); } return preg_replace('{^file://}i', '', $path); diff --git a/tests/Composer/Test/Json/JsonManipulatorTest.php b/tests/Composer/Test/Json/JsonManipulatorTest.php index 76e39fb95..afb53774e 100644 --- a/tests/Composer/Test/Json/JsonManipulatorTest.php +++ b/tests/Composer/Test/Json/JsonManipulatorTest.php @@ -2045,6 +2045,31 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase ', $manipulator->getContents()); } + public function testAddMainKeyWithContentHavingDollarSignFollowedByDigit() + { + $manipulator = new JsonManipulator('{ + "foo": "bar" +}'); + + $this->assertTrue($manipulator->addMainKey('bar', '$1baz')); + $this->assertEquals('{ + "foo": "bar", + "bar": "$1baz" +} +', $manipulator->getContents()); + } + + public function testAddMainKeyWithContentHavingDollarSignFollowedByDigit2() + { + $manipulator = new JsonManipulator('{}'); + + $this->assertTrue($manipulator->addMainKey('foo', '$1bar')); + $this->assertEquals('{ + "foo": "$1bar" +} +', $manipulator->getContents()); + } + public function testUpdateMainKey() { $manipulator = new JsonManipulator('{ @@ -2105,6 +2130,19 @@ class JsonManipulatorTest extends \PHPUnit_Framework_TestCase ', $manipulator->getContents()); } + public function testUpdateMainKeyWithContentHavingDollarSignFollowedByDigit() + { + $manipulator = new JsonManipulator('{ + "foo": "bar" +}'); + + $this->assertTrue($manipulator->addMainKey('foo', '$1bar')); + $this->assertEquals('{ + "foo": "$1bar" +} +', $manipulator->getContents()); + } + public function testIndentDetection() { $manipulator = new JsonManipulator('{