Browse Source

Merge remote-tracking branch 'digitalkaoz/issue_347'

Jordi Boggiano 12 years ago
parent
commit
ae2fb6be89

+ 11 - 8
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,23 @@ 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 new JsonValidationException('JSON file is not valid "'.$file.'"'."\n".$result->getMessage(), $result->getDetails());
     }
 }

+ 2 - 2
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()

+ 1 - 1
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);
         }

+ 11 - 6
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'];

+ 3 - 2
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);

+ 10 - 6
src/Composer/Repository/Vcs/GitHubDriver.php

@@ -127,7 +127,8 @@ class GitHubDriver extends VcsDriver
 
         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 +138,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 +173,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 +193,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 +249,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'])) {

+ 11 - 6
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'];

+ 1 - 1
src/Composer/Repository/Vcs/HgDriver.php

@@ -100,7 +100,7 @@ class HgDriver extends VcsDriver
                 return;
             }
 
-            $composer = JsonFile::parseJson($composer);
+            $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);

+ 3 - 2
src/Composer/Repository/Vcs/SvnDriver.php

@@ -107,7 +107,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 +116,7 @@ class SvnDriver extends VcsDriver
                 throw new TransportException($e->getMessage());
             }
 
-            $composer = JsonFile::parseJson($output);
+            $composer = JsonFile::parseJson($output, $this->baseUrl . $resource . $rev);
 
             if (!isset($composer['time'])) {
                 $output = $this->execute('svn info', $this->baseUrl . $path . $rev);

+ 3 - 1
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,8 +198,9 @@ class JsonFileTest extends \PHPUnit_Framework_TestCase
         try {
             JsonFile::parseJson($json);
             $this->fail();
-        } catch (ParsingException $e) {
+        } catch (JsonValidationException $e) {
             $this->assertContains($text, $e->getMessage());
+            $this->assertNotEmpty($e->getErrors());
         }
     }