From c517ac640423a17418ff7b57100a66d244d9b07a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=B6nthal?= Date: Mon, 2 Jul 2012 11:32:26 +0200 Subject: [PATCH 1/3] fixed issue #347 added file to json validation exception --- src/Composer/Json/JsonFile.php | 20 +++++++++++-------- src/Composer/Json/JsonValidationException.php | 4 ++-- src/Composer/Package/Loader/JsonLoader.php | 2 +- .../Repository/Vcs/GitBitbucketDriver.php | 17 ++++++++++------ src/Composer/Repository/Vcs/GitDriver.php | 5 +++-- src/Composer/Repository/Vcs/GitHubDriver.php | 17 ++++++++++------ .../Repository/Vcs/HgBitbucketDriver.php | 17 ++++++++++------ src/Composer/Repository/Vcs/HgDriver.php | 5 +++-- src/Composer/Repository/Vcs/SvnDriver.php | 6 ++++-- tests/Composer/Test/Json/JsonFileTest.php | 3 ++- 10 files changed, 60 insertions(+), 36 deletions(-) diff --git a/src/Composer/Json/JsonFile.php b/src/Composer/Json/JsonFile.php index 16675deb4..3c3f731fd 100644 --- a/src/Composer/Json/JsonFile.php +++ b/src/Composer/Json/JsonFile.php @@ -86,7 +86,7 @@ class JsonFile throw new \RuntimeException('Could not read '.$this->path."\n\n".$e->getMessage()); } - return static::parseJson($json); + return static::parseJson($json, $this->path); } /** @@ -126,7 +126,7 @@ class JsonFile $data = json_decode($content); if (null === $data && 'null' !== $content) { - self::validateSyntax($content); + self::validateSyntax($content, $this->path); } $schemaFile = __DIR__ . '/../../../res/composer-schema.json'; @@ -148,7 +148,7 @@ class JsonFile foreach ((array) $validator->getErrors() as $error) { $errors[] = ($error['property'] ? $error['property'].' : ' : '').$error['message']; } - throw new JsonValidationException($errors); + throw new JsonValidationException('JSON file doesnt match expected schema "'.$this->path.'"', $errors); } return true; @@ -265,14 +265,15 @@ class JsonFile * Parses json string and returns hash. * * @param string $json json string + * @param string $file the json file * * @return mixed */ - public static function parseJson($json) + public static function parseJson($json, $file = null) { $data = json_decode($json, true); if (null === $data && JSON_ERROR_NONE !== json_last_error()) { - self::validateSyntax($json); + self::validateSyntax($json, $file); } return $data; @@ -282,21 +283,24 @@ class JsonFile * Validates the syntax of a JSON string * * @param string $json + * @param string $file * @return bool true on success * @throws \UnexpectedValueException + * @throws JsonValidationException */ - protected static function validateSyntax($json) + protected static function validateSyntax($json, $file = null) { $parser = new JsonParser(); $result = $parser->lint($json); if (null === $result) { if (defined('JSON_ERROR_UTF8') && JSON_ERROR_UTF8 === json_last_error()) { - throw new \UnexpectedValueException('JSON file is not UTF-8 encoded'); + throw new \UnexpectedValueException('JSON file is not UTF-8 encoded "'.$file.'"'); } return true; } - throw $result; + //throw $result; + throw new JsonValidationException('JSON file is not valid "'.$file.'"'."\n".$result->getMessage(), $result->getDetails()); } } diff --git a/src/Composer/Json/JsonValidationException.php b/src/Composer/Json/JsonValidationException.php index 30bef88b6..0b2b2ba70 100644 --- a/src/Composer/Json/JsonValidationException.php +++ b/src/Composer/Json/JsonValidationException.php @@ -21,10 +21,10 @@ class JsonValidationException extends Exception { protected $errors; - public function __construct(array $errors) + public function __construct($message, $errors = array()) { - parent::__construct(implode("\n", $errors)); $this->errors = $errors; + parent::__construct($message); } public function getErrors() diff --git a/src/Composer/Package/Loader/JsonLoader.php b/src/Composer/Package/Loader/JsonLoader.php index 27ff7c15a..fcecc0014 100644 --- a/src/Composer/Package/Loader/JsonLoader.php +++ b/src/Composer/Package/Loader/JsonLoader.php @@ -24,7 +24,7 @@ class JsonLoader extends ArrayLoader if ($json instanceof JsonFile) { $config = $json->read(); } elseif (file_exists($json)) { - $config = JsonFile::parseJson(file_get_contents($json)); + $config = JsonFile::parseJson(file_get_contents($json), $json); } elseif (is_string($json)) { $config = JsonFile::parseJson($json); } diff --git a/src/Composer/Repository/Vcs/GitBitbucketDriver.php b/src/Composer/Repository/Vcs/GitBitbucketDriver.php index 0ed579fa4..b0daaba5d 100644 --- a/src/Composer/Repository/Vcs/GitBitbucketDriver.php +++ b/src/Composer/Repository/Vcs/GitBitbucketDriver.php @@ -44,7 +44,8 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface public function getRootIdentifier() { if (null === $this->rootIdentifier) { - $repoData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository)); + $resource = $this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository; + $repoData = JsonFile::parseJson($this->getContents($resource), $resource); $this->rootIdentifier = !empty($repoData['main_branch']) ? $repoData['main_branch'] : 'master'; } @@ -86,15 +87,17 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface public function getComposerInformation($identifier) { if (!isset($this->infoCache[$identifier])) { - $composer = $this->getContents($this->getScheme() . '://bitbucket.org/'.$this->owner.'/'.$this->repository.'/raw/'.$identifier.'/composer.json'); + $resource = $this->getScheme() . '://bitbucket.org/'.$this->owner.'/'.$this->repository.'/raw/'.$identifier.'/composer.json'; + $composer = $this->getContents($resource); if (!$composer) { return; } - $composer = JsonFile::parseJson($composer); + $composer = JsonFile::parseJson($composer, $resource); if (!isset($composer['time'])) { - $changeset = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/changesets/'.$identifier)); + $resource = $this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/changesets/'.$identifier; + $changeset = JsonFile::parseJson($this->getContents($resource), $resource); $composer['time'] = $changeset['timestamp']; } $this->infoCache[$identifier] = $composer; @@ -109,7 +112,8 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface public function getTags() { if (null === $this->tags) { - $tagsData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags')); + $resource = $this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags'; + $tagsData = JsonFile::parseJson($this->getContents($resource), $resource); $this->tags = array(); foreach ($tagsData as $tag => $data) { $this->tags[$tag] = $data['raw_node']; @@ -125,7 +129,8 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface public function getBranches() { if (null === $this->branches) { - $branchData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/branches')); + $resource = $this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/branches'; + $branchData = JsonFile::parseJson($this->getContents($resource), $resource); $this->branches = array(); foreach ($branchData as $branch => $data) { $this->branches[$branch] = $data['raw_node']; diff --git a/src/Composer/Repository/Vcs/GitDriver.php b/src/Composer/Repository/Vcs/GitDriver.php index f31d27bb6..dca7366e2 100644 --- a/src/Composer/Repository/Vcs/GitDriver.php +++ b/src/Composer/Repository/Vcs/GitDriver.php @@ -123,13 +123,14 @@ class GitDriver extends VcsDriver public function getComposerInformation($identifier) { if (!isset($this->infoCache[$identifier])) { - $this->process->execute(sprintf('git show %s:composer.json', escapeshellarg($identifier)), $composer, $this->repoDir); + $resource = sprintf('%s:composer.json', escapeshellarg($identifier)); + $this->process->execute(sprintf('git show %s', $resource), $composer, $this->repoDir); if (!trim($composer)) { return; } - $composer = JsonFile::parseJson($composer); + $composer = JsonFile::parseJson($composer, $resource); if (!isset($composer['time'])) { $this->process->execute(sprintf('git log -1 --format=%%at %s', escapeshellarg($identifier)), $output, $this->repoDir); diff --git a/src/Composer/Repository/Vcs/GitHubDriver.php b/src/Composer/Repository/Vcs/GitHubDriver.php index 87d210af4..5e924254f 100644 --- a/src/Composer/Repository/Vcs/GitHubDriver.php +++ b/src/Composer/Repository/Vcs/GitHubDriver.php @@ -122,12 +122,14 @@ class GitHubDriver extends VcsDriver } if (preg_match('{[a-f0-9]{40}}i', $identifier) && $res = $this->cache->read($identifier)) { + //TODO how to get the json file here? $this->infoCache[$identifier] = JsonFile::parseJson($res); } if (!isset($this->infoCache[$identifier])) { try { - $composer = $this->getContents('https://raw.github.com/'.$this->owner.'/'.$this->repository.'/'.$identifier.'/composer.json'); + $resource = 'https://raw.github.com/'.$this->owner.'/'.$this->repository.'/'.$identifier.'/composer.json'; + $composer = $this->getContents($resource); } catch (TransportException $e) { if (404 !== $e->getCode()) { throw $e; @@ -137,10 +139,11 @@ class GitHubDriver extends VcsDriver } if ($composer) { - $composer = JsonFile::parseJson($composer); + $composer = JsonFile::parseJson($composer, $resource); if (!isset($composer['time'])) { - $commit = JsonFile::parseJson($this->getContents('https://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/commits/'.$identifier)); + $resource = 'https://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/commits/'.$identifier; + $commit = JsonFile::parseJson($this->getContents($resource), $resource); $composer['time'] = $commit['commit']['committer']['date']; } if (!isset($composer['support']['source'])) { @@ -171,7 +174,8 @@ class GitHubDriver extends VcsDriver return $this->gitDriver->getTags(); } if (null === $this->tags) { - $tagsData = JsonFile::parseJson($this->getContents('https://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/tags')); + $resource = 'https://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/tags'; + $tagsData = JsonFile::parseJson($this->getContents($resource), $resource); $this->tags = array(); foreach ($tagsData as $tag) { $this->tags[$tag['name']] = $tag['commit']['sha']; @@ -190,7 +194,8 @@ class GitHubDriver extends VcsDriver return $this->gitDriver->getBranches(); } if (null === $this->branches) { - $branchData = JsonFile::parseJson($this->getContents('https://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/git/refs/heads')); + $resource = 'https://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/git/refs/heads'; + $branchData = JsonFile::parseJson($this->getContents($resource), $resource); $this->branches = array(); foreach ($branchData as $branch) { $name = substr($branch['ref'], 11); @@ -245,7 +250,7 @@ class GitHubDriver extends VcsDriver throw new \RuntimeException("Either you have entered invalid credentials or this GitHub repository does not exists (404)"); } try { - $repoData = JsonFile::parseJson($this->getContents($repoDataUrl)); + $repoData = JsonFile::parseJson($this->getContents($repoDataUrl), $repoDataUrl); if (isset($repoData['default_branch'])) { $this->rootIdentifier = $repoData['default_branch']; } elseif (isset($repoData['master_branch'])) { diff --git a/src/Composer/Repository/Vcs/HgBitbucketDriver.php b/src/Composer/Repository/Vcs/HgBitbucketDriver.php index d0d1097b2..f31f61c44 100644 --- a/src/Composer/Repository/Vcs/HgBitbucketDriver.php +++ b/src/Composer/Repository/Vcs/HgBitbucketDriver.php @@ -44,7 +44,8 @@ class HgBitbucketDriver extends VcsDriver public function getRootIdentifier() { if (null === $this->rootIdentifier) { - $repoData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags')); + $resource = $this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags'; + $repoData = JsonFile::parseJson($this->getContents($resource), $resource); $this->rootIdentifier = $repoData['tip']['raw_node']; } @@ -86,15 +87,17 @@ class HgBitbucketDriver extends VcsDriver public function getComposerInformation($identifier) { if (!isset($this->infoCache[$identifier])) { - $composer = $this->getContents($this->getScheme() . '://bitbucket.org/'.$this->owner.'/'.$this->repository.'/raw/'.$identifier.'/composer.json'); + $resource = $this->getScheme() . '://bitbucket.org/'.$this->owner.'/'.$this->repository.'/raw/'.$identifier.'/composer.json'; + $composer = $this->getContents($resource); if (!$composer) { return; } - $composer = JsonFile::parseJson($composer); + $composer = JsonFile::parseJson($composer, $resource); if (!isset($composer['time'])) { - $changeset = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/changesets/'.$identifier)); + $resource = $this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/changesets/'.$identifier; + $changeset = JsonFile::parseJson($this->getContents($resource), $resource); $composer['time'] = $changeset['timestamp']; } $this->infoCache[$identifier] = $composer; @@ -109,7 +112,8 @@ class HgBitbucketDriver extends VcsDriver public function getTags() { if (null === $this->tags) { - $tagsData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags')); + $resource = $this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags'; + $tagsData = JsonFile::parseJson($this->getContents($resource), $resource); $this->tags = array(); foreach ($tagsData as $tag => $data) { $this->tags[$tag] = $data['raw_node']; @@ -125,7 +129,8 @@ class HgBitbucketDriver extends VcsDriver public function getBranches() { if (null === $this->branches) { - $branchData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/branches')); + $resource = $this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/branches'; + $branchData = JsonFile::parseJson($this->getContents($resource), $resource); $this->branches = array(); foreach ($branchData as $branch => $data) { $this->branches[$branch] = $data['raw_node']; diff --git a/src/Composer/Repository/Vcs/HgDriver.php b/src/Composer/Repository/Vcs/HgDriver.php index 1008bbe90..31ed5c57c 100644 --- a/src/Composer/Repository/Vcs/HgDriver.php +++ b/src/Composer/Repository/Vcs/HgDriver.php @@ -94,13 +94,14 @@ class HgDriver extends VcsDriver public function getComposerInformation($identifier) { if (!isset($this->infoCache[$identifier])) { - $this->process->execute(sprintf('cd %s && hg cat -r %s composer.json', escapeshellarg($this->tmpDir), escapeshellarg($identifier)), $composer); + $resource = escapeshellarg($identifier); + $this->process->execute(sprintf('cd %s && hg cat -r %s composer.json', escapeshellarg($this->tmpDir), $resource), $composer); if (!trim($composer)) { return; } - $composer = JsonFile::parseJson($composer); + $composer = JsonFile::parseJson($composer, $resource); if (!isset($composer['time'])) { $this->process->execute(sprintf('cd %s && hg log --template "{date|rfc822date}" -r %s', escapeshellarg($this->tmpDir), escapeshellarg($identifier)), $output); diff --git a/src/Composer/Repository/Vcs/SvnDriver.php b/src/Composer/Repository/Vcs/SvnDriver.php index 1d087aad5..bc1ed69b2 100644 --- a/src/Composer/Repository/Vcs/SvnDriver.php +++ b/src/Composer/Repository/Vcs/SvnDriver.php @@ -94,6 +94,7 @@ class SvnDriver extends VcsDriver $identifier = '/' . trim($identifier, '/') . '/'; if ($res = $this->cache->read($identifier.'.json')) { + //TODO how to get the json filename here? $this->infoCache[$identifier] = JsonFile::parseJson($res); } @@ -107,7 +108,8 @@ class SvnDriver extends VcsDriver } try { - $output = $this->execute('svn cat', $this->baseUrl . $path . 'composer.json' . $rev); + $resource = $path.'composer.json'; + $output = $this->execute('svn cat', $this->baseUrl . $resource . $rev); if (!trim($output)) { return; } @@ -115,7 +117,7 @@ class SvnDriver extends VcsDriver throw new TransportException($e->getMessage()); } - $composer = JsonFile::parseJson($output); + $composer = JsonFile::parseJson($output, $resource); if (!isset($composer['time'])) { $output = $this->execute('svn info', $this->baseUrl . $path . $rev); diff --git a/tests/Composer/Test/Json/JsonFileTest.php b/tests/Composer/Test/Json/JsonFileTest.php index 159017aa6..f918d538b 100644 --- a/tests/Composer/Test/Json/JsonFileTest.php +++ b/tests/Composer/Test/Json/JsonFileTest.php @@ -13,6 +13,7 @@ namespace Composer\Test\Json; use Seld\JsonLint\ParsingException; +use Composer\Json\JsonValidationException; use Composer\Json\JsonFile; class JsonFileTest extends \PHPUnit_Framework_TestCase @@ -197,7 +198,7 @@ class JsonFileTest extends \PHPUnit_Framework_TestCase try { JsonFile::parseJson($json); $this->fail(); - } catch (ParsingException $e) { + } catch (JsonValidationException $e) { $this->assertContains($text, $e->getMessage()); } } From e96e06946fce15ee60c529a13cd884537cb3f860 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=B6nthal?= Date: Mon, 2 Jul 2012 15:13:56 +0200 Subject: [PATCH 2/3] fixed json file tests --- tests/Composer/Test/Json/JsonFileTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Composer/Test/Json/JsonFileTest.php b/tests/Composer/Test/Json/JsonFileTest.php index f918d538b..55bf603ea 100644 --- a/tests/Composer/Test/Json/JsonFileTest.php +++ b/tests/Composer/Test/Json/JsonFileTest.php @@ -200,6 +200,7 @@ class JsonFileTest extends \PHPUnit_Framework_TestCase $this->fail(); } catch (JsonValidationException $e) { $this->assertContains($text, $e->getMessage()); + $this->assertNotEmpty($e->getErrors()); } } From 0cd453449b4807e315aea9a3e8418b96331923fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=B6nthal?= Date: Tue, 3 Jul 2012 12:42:29 +0200 Subject: [PATCH 3/3] minor changes to JsonFile::parseJson for Drivers --- src/Composer/Json/JsonFile.php | 1 - src/Composer/Repository/Vcs/GitHubDriver.php | 1 - src/Composer/Repository/Vcs/HgDriver.php | 5 ++--- src/Composer/Repository/Vcs/SvnDriver.php | 3 +-- 4 files changed, 3 insertions(+), 7 deletions(-) mode change 100644 => 100755 src/Composer/Json/JsonFile.php mode change 100644 => 100755 src/Composer/Repository/Vcs/GitHubDriver.php mode change 100644 => 100755 src/Composer/Repository/Vcs/HgDriver.php mode change 100644 => 100755 src/Composer/Repository/Vcs/SvnDriver.php diff --git a/src/Composer/Json/JsonFile.php b/src/Composer/Json/JsonFile.php old mode 100644 new mode 100755 index 3c3f731fd..dc2538132 --- a/src/Composer/Json/JsonFile.php +++ b/src/Composer/Json/JsonFile.php @@ -300,7 +300,6 @@ class JsonFile return true; } - //throw $result; throw new JsonValidationException('JSON file is not valid "'.$file.'"'."\n".$result->getMessage(), $result->getDetails()); } } diff --git a/src/Composer/Repository/Vcs/GitHubDriver.php b/src/Composer/Repository/Vcs/GitHubDriver.php old mode 100644 new mode 100755 index 5e924254f..57a2f4f8b --- a/src/Composer/Repository/Vcs/GitHubDriver.php +++ b/src/Composer/Repository/Vcs/GitHubDriver.php @@ -122,7 +122,6 @@ class GitHubDriver extends VcsDriver } if (preg_match('{[a-f0-9]{40}}i', $identifier) && $res = $this->cache->read($identifier)) { - //TODO how to get the json file here? $this->infoCache[$identifier] = JsonFile::parseJson($res); } diff --git a/src/Composer/Repository/Vcs/HgDriver.php b/src/Composer/Repository/Vcs/HgDriver.php old mode 100644 new mode 100755 index 31ed5c57c..c7cea695a --- a/src/Composer/Repository/Vcs/HgDriver.php +++ b/src/Composer/Repository/Vcs/HgDriver.php @@ -94,14 +94,13 @@ class HgDriver extends VcsDriver public function getComposerInformation($identifier) { if (!isset($this->infoCache[$identifier])) { - $resource = escapeshellarg($identifier); - $this->process->execute(sprintf('cd %s && hg cat -r %s composer.json', escapeshellarg($this->tmpDir), $resource), $composer); + $this->process->execute(sprintf('cd %s && hg cat -r %s composer.json', escapeshellarg($this->tmpDir), escapeshellarg($identifier)), $composer); if (!trim($composer)) { return; } - $composer = JsonFile::parseJson($composer, $resource); + $composer = JsonFile::parseJson($composer, $identifier); if (!isset($composer['time'])) { $this->process->execute(sprintf('cd %s && hg log --template "{date|rfc822date}" -r %s', escapeshellarg($this->tmpDir), escapeshellarg($identifier)), $output); diff --git a/src/Composer/Repository/Vcs/SvnDriver.php b/src/Composer/Repository/Vcs/SvnDriver.php old mode 100644 new mode 100755 index bc1ed69b2..1589ffb04 --- a/src/Composer/Repository/Vcs/SvnDriver.php +++ b/src/Composer/Repository/Vcs/SvnDriver.php @@ -94,7 +94,6 @@ class SvnDriver extends VcsDriver $identifier = '/' . trim($identifier, '/') . '/'; if ($res = $this->cache->read($identifier.'.json')) { - //TODO how to get the json filename here? $this->infoCache[$identifier] = JsonFile::parseJson($res); } @@ -117,7 +116,7 @@ class SvnDriver extends VcsDriver throw new TransportException($e->getMessage()); } - $composer = JsonFile::parseJson($output, $resource); + $composer = JsonFile::parseJson($output, $this->baseUrl . $resource . $rev); if (!isset($composer['time'])) { $output = $this->execute('svn info', $this->baseUrl . $path . $rev);