1
0
Fork 0

Merge remote-tracking branch 'digitalkaoz/issue_347'

pull/868/merge
Jordi Boggiano 2012-07-03 13:19:40 +02:00
commit ae2fb6be89
10 changed files with 56 additions and 35 deletions

19
src/Composer/Json/JsonFile.php Normal file → Executable file
View File

@ -86,7 +86,7 @@ class JsonFile
throw new \RuntimeException('Could not read '.$this->path."\n\n".$e->getMessage()); 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); $data = json_decode($content);
if (null === $data && 'null' !== $content) { if (null === $data && 'null' !== $content) {
self::validateSyntax($content); self::validateSyntax($content, $this->path);
} }
$schemaFile = __DIR__ . '/../../../res/composer-schema.json'; $schemaFile = __DIR__ . '/../../../res/composer-schema.json';
@ -148,7 +148,7 @@ class JsonFile
foreach ((array) $validator->getErrors() as $error) { foreach ((array) $validator->getErrors() as $error) {
$errors[] = ($error['property'] ? $error['property'].' : ' : '').$error['message']; $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; return true;
@ -265,14 +265,15 @@ class JsonFile
* Parses json string and returns hash. * Parses json string and returns hash.
* *
* @param string $json json string * @param string $json json string
* @param string $file the json file
* *
* @return mixed * @return mixed
*/ */
public static function parseJson($json) public static function parseJson($json, $file = null)
{ {
$data = json_decode($json, true); $data = json_decode($json, true);
if (null === $data && JSON_ERROR_NONE !== json_last_error()) { if (null === $data && JSON_ERROR_NONE !== json_last_error()) {
self::validateSyntax($json); self::validateSyntax($json, $file);
} }
return $data; return $data;
@ -282,21 +283,23 @@ class JsonFile
* Validates the syntax of a JSON string * Validates the syntax of a JSON string
* *
* @param string $json * @param string $json
* @param string $file
* @return bool true on success * @return bool true on success
* @throws \UnexpectedValueException * @throws \UnexpectedValueException
* @throws JsonValidationException
*/ */
protected static function validateSyntax($json) protected static function validateSyntax($json, $file = null)
{ {
$parser = new JsonParser(); $parser = new JsonParser();
$result = $parser->lint($json); $result = $parser->lint($json);
if (null === $result) { if (null === $result) {
if (defined('JSON_ERROR_UTF8') && JSON_ERROR_UTF8 === json_last_error()) { 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; return true;
} }
throw $result; throw new JsonValidationException('JSON file is not valid "'.$file.'"'."\n".$result->getMessage(), $result->getDetails());
} }
} }

View File

@ -21,10 +21,10 @@ class JsonValidationException extends Exception
{ {
protected $errors; protected $errors;
public function __construct(array $errors) public function __construct($message, $errors = array())
{ {
parent::__construct(implode("\n", $errors));
$this->errors = $errors; $this->errors = $errors;
parent::__construct($message);
} }
public function getErrors() public function getErrors()

View File

@ -24,7 +24,7 @@ class JsonLoader extends ArrayLoader
if ($json instanceof JsonFile) { if ($json instanceof JsonFile) {
$config = $json->read(); $config = $json->read();
} elseif (file_exists($json)) { } elseif (file_exists($json)) {
$config = JsonFile::parseJson(file_get_contents($json)); $config = JsonFile::parseJson(file_get_contents($json), $json);
} elseif (is_string($json)) { } elseif (is_string($json)) {
$config = JsonFile::parseJson($json); $config = JsonFile::parseJson($json);
} }

View File

@ -44,7 +44,8 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface
public function getRootIdentifier() public function getRootIdentifier()
{ {
if (null === $this->rootIdentifier) { 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'; $this->rootIdentifier = !empty($repoData['main_branch']) ? $repoData['main_branch'] : 'master';
} }
@ -86,15 +87,17 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface
public function getComposerInformation($identifier) public function getComposerInformation($identifier)
{ {
if (!isset($this->infoCache[$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) { if (!$composer) {
return; return;
} }
$composer = JsonFile::parseJson($composer); $composer = JsonFile::parseJson($composer, $resource);
if (!isset($composer['time'])) { 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']; $composer['time'] = $changeset['timestamp'];
} }
$this->infoCache[$identifier] = $composer; $this->infoCache[$identifier] = $composer;
@ -109,7 +112,8 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface
public function getTags() public function getTags()
{ {
if (null === $this->tags) { 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(); $this->tags = array();
foreach ($tagsData as $tag => $data) { foreach ($tagsData as $tag => $data) {
$this->tags[$tag] = $data['raw_node']; $this->tags[$tag] = $data['raw_node'];
@ -125,7 +129,8 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface
public function getBranches() public function getBranches()
{ {
if (null === $this->branches) { 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(); $this->branches = array();
foreach ($branchData as $branch => $data) { foreach ($branchData as $branch => $data) {
$this->branches[$branch] = $data['raw_node']; $this->branches[$branch] = $data['raw_node'];

View File

@ -123,13 +123,14 @@ class GitDriver extends VcsDriver
public function getComposerInformation($identifier) public function getComposerInformation($identifier)
{ {
if (!isset($this->infoCache[$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)) { if (!trim($composer)) {
return; return;
} }
$composer = JsonFile::parseJson($composer); $composer = JsonFile::parseJson($composer, $resource);
if (!isset($composer['time'])) { if (!isset($composer['time'])) {
$this->process->execute(sprintf('git log -1 --format=%%at %s', escapeshellarg($identifier)), $output, $this->repoDir); $this->process->execute(sprintf('git log -1 --format=%%at %s', escapeshellarg($identifier)), $output, $this->repoDir);

16
src/Composer/Repository/Vcs/GitHubDriver.php Normal file → Executable file
View File

@ -127,7 +127,8 @@ class GitHubDriver extends VcsDriver
if (!isset($this->infoCache[$identifier])) { if (!isset($this->infoCache[$identifier])) {
try { 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) { } catch (TransportException $e) {
if (404 !== $e->getCode()) { if (404 !== $e->getCode()) {
throw $e; throw $e;
@ -137,10 +138,11 @@ class GitHubDriver extends VcsDriver
} }
if ($composer) { if ($composer) {
$composer = JsonFile::parseJson($composer); $composer = JsonFile::parseJson($composer, $resource);
if (!isset($composer['time'])) { 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']; $composer['time'] = $commit['commit']['committer']['date'];
} }
if (!isset($composer['support']['source'])) { if (!isset($composer['support']['source'])) {
@ -171,7 +173,8 @@ class GitHubDriver extends VcsDriver
return $this->gitDriver->getTags(); return $this->gitDriver->getTags();
} }
if (null === $this->tags) { 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(); $this->tags = array();
foreach ($tagsData as $tag) { foreach ($tagsData as $tag) {
$this->tags[$tag['name']] = $tag['commit']['sha']; $this->tags[$tag['name']] = $tag['commit']['sha'];
@ -190,7 +193,8 @@ class GitHubDriver extends VcsDriver
return $this->gitDriver->getBranches(); return $this->gitDriver->getBranches();
} }
if (null === $this->branches) { 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(); $this->branches = array();
foreach ($branchData as $branch) { foreach ($branchData as $branch) {
$name = substr($branch['ref'], 11); $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)"); throw new \RuntimeException("Either you have entered invalid credentials or this GitHub repository does not exists (404)");
} }
try { try {
$repoData = JsonFile::parseJson($this->getContents($repoDataUrl)); $repoData = JsonFile::parseJson($this->getContents($repoDataUrl), $repoDataUrl);
if (isset($repoData['default_branch'])) { if (isset($repoData['default_branch'])) {
$this->rootIdentifier = $repoData['default_branch']; $this->rootIdentifier = $repoData['default_branch'];
} elseif (isset($repoData['master_branch'])) { } elseif (isset($repoData['master_branch'])) {

View File

@ -44,7 +44,8 @@ class HgBitbucketDriver extends VcsDriver
public function getRootIdentifier() public function getRootIdentifier()
{ {
if (null === $this->rootIdentifier) { 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']; $this->rootIdentifier = $repoData['tip']['raw_node'];
} }
@ -86,15 +87,17 @@ class HgBitbucketDriver extends VcsDriver
public function getComposerInformation($identifier) public function getComposerInformation($identifier)
{ {
if (!isset($this->infoCache[$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) { if (!$composer) {
return; return;
} }
$composer = JsonFile::parseJson($composer); $composer = JsonFile::parseJson($composer, $resource);
if (!isset($composer['time'])) { 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']; $composer['time'] = $changeset['timestamp'];
} }
$this->infoCache[$identifier] = $composer; $this->infoCache[$identifier] = $composer;
@ -109,7 +112,8 @@ class HgBitbucketDriver extends VcsDriver
public function getTags() public function getTags()
{ {
if (null === $this->tags) { 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(); $this->tags = array();
foreach ($tagsData as $tag => $data) { foreach ($tagsData as $tag => $data) {
$this->tags[$tag] = $data['raw_node']; $this->tags[$tag] = $data['raw_node'];
@ -125,7 +129,8 @@ class HgBitbucketDriver extends VcsDriver
public function getBranches() public function getBranches()
{ {
if (null === $this->branches) { 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(); $this->branches = array();
foreach ($branchData as $branch => $data) { foreach ($branchData as $branch => $data) {
$this->branches[$branch] = $data['raw_node']; $this->branches[$branch] = $data['raw_node'];

2
src/Composer/Repository/Vcs/HgDriver.php Normal file → Executable file
View File

@ -100,7 +100,7 @@ class HgDriver extends VcsDriver
return; return;
} }
$composer = JsonFile::parseJson($composer); $composer = JsonFile::parseJson($composer, $identifier);
if (!isset($composer['time'])) { if (!isset($composer['time'])) {
$this->process->execute(sprintf('cd %s && hg log --template "{date|rfc822date}" -r %s', escapeshellarg($this->tmpDir), escapeshellarg($identifier)), $output); $this->process->execute(sprintf('cd %s && hg log --template "{date|rfc822date}" -r %s', escapeshellarg($this->tmpDir), escapeshellarg($identifier)), $output);

5
src/Composer/Repository/Vcs/SvnDriver.php Normal file → Executable file
View File

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

View File

@ -13,6 +13,7 @@
namespace Composer\Test\Json; namespace Composer\Test\Json;
use Seld\JsonLint\ParsingException; use Seld\JsonLint\ParsingException;
use Composer\Json\JsonValidationException;
use Composer\Json\JsonFile; use Composer\Json\JsonFile;
class JsonFileTest extends \PHPUnit_Framework_TestCase class JsonFileTest extends \PHPUnit_Framework_TestCase
@ -197,8 +198,9 @@ class JsonFileTest extends \PHPUnit_Framework_TestCase
try { try {
JsonFile::parseJson($json); JsonFile::parseJson($json);
$this->fail(); $this->fail();
} catch (ParsingException $e) { } catch (JsonValidationException $e) {
$this->assertContains($text, $e->getMessage()); $this->assertContains($text, $e->getMessage());
$this->assertNotEmpty($e->getErrors());
} }
} }