Permalink
Browse files

added schema/syntax validation for composer.json

  • Loading branch information...
1 parent a161978 commit 6929c42848ea843a0652e93bcad0ddbf193f4f9f @digitalkaoz digitalkaoz committed Dec 9, 2011
View
@@ -1,151 +0,0 @@
-#!/usr/bin/env php
-<?php
-
-/*
- * This file is part of Composer.
- *
- * (c) Nils Adermann <naderman@naderman.de>
- * Jordi Boggiano <j.boggiano@seld.be>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-
-process($argv);
-
-/**
- * processes the installer
- */
-function process($argv)
-{
- $check = in_array('--check', $argv);
- $help = in_array('--help', $argv);
- $force = in_array('--force', $argv);
-
- if ($help) {
- displayHelp();
- exit(0);
- }
-
- $ok = checkPlatform();
-
- if ($check && !$ok) {
- exit(1);
- }
-
- if ($ok || $force) {
- installComposer();
- }
-
- exit(0);
-}
-
-/**
- * displays the help
- */
-function displayHelp()
-{
- echo <<<EOF
-Composer Installer
-------------------
-Options
---help this help
---check for checking environment only
---force forces the installation
-
-EOF;
-}
-
-/**
- * check the platform for possible issues on running composer
- */
-function checkPlatform()
-{
- $errors = array();
- if (false !== ini_get('detect_unicode')) {
- $errors['unicode'] = 'On';
- }
-
- if (ini_get('phar.readonly')) {
- $errors['readonly'] = 'On';
- }
-
- if (ini_get('phar.require_hash')) {
- $errors['require_hash'] = 'On';
- }
-
- if ($suhosin = ini_get('suhosin.executor.include.whitelist') && (isset($suhosin) && false === stripos($suhosin, 'phar'))) {
- $errors['suhosin'] = $suhosin;
- }
-
- if (PHP_VERSION < '5.3.2') {
- $errors['php'] = PHP_VERSION;
- }
-
- if (!empty($errors)) {
- out("Composer detected that you have enabled some settings in your `php.ini` file that can make Composer unable to work properly.".PHP_EOL, 'error');
-
- echo PHP_EOL.'Make sure that you have changed options listed below:'.PHP_EOL;
- foreach ($errors as $error => $actual) {
- switch ($error) {
- case 'unicode':
- $text = " detect_unicode = Off (actual: {$actual})".PHP_EOL;
- break;
-
- case 'readonly':
- $text = " phar.readonly = Off (actual: {$actual})".PHP_EOL;
- break;
-
- case 'require_hash':
- $text = " phar.require_hash = Off (actual: {$actual})".PHP_EOL;
- break;
-
- case 'suhosin':
- $text = " suhosin.executor.include.whitelist = phar (actual: {$actual})".PHP_EOL;
- break;
- case 'php':
- $text = " PHP_VERSION (actual: {$actual})".PHP_EOL;
- break;
- }
- out($text, 'info');
- }
- echo PHP_EOL;
- return false;
- }
-
- out("All settings correct for using Composer".PHP_EOL,'success');
- return true;
-}
-
-/**
- * installs composer to the current working directory
- */
-function installComposer()
-{
- $installDir = getcwd();
- $file = $installDir . DIRECTORY_SEPARATOR . 'composer.phar';
-
- if (is_readable($file)) {
- @unlink($file);
- }
-
- $download = copy('http://getcomposer.org/composer.phar', $installDir.DIRECTORY_SEPARATOR.'composer.phar');
-
- out(PHP_EOL."Composer successfully installed to: " . $file, 'success');
- out(PHP_EOL."Use it: php composer.phar".PHP_EOL, 'info');
-}
-
-/**
- * colorize output
- */
-function out($text, $color = null)
-{
- $styles = array(
- 'success' => "\033[0;32m%s\033[0m",
- 'error' => "\033[31;31m%s\033[0m",
- 'info' => "\033[33;33m%s\033[0m"
- );
-
- echo sprintf(isset($styles[$color]) ? $styles[$color] : "%s", $text);
-}
View
@@ -18,7 +18,9 @@
}
],
"require": {
- "php": ">=5.3.0",
+ "php": ">=5.3.0",
+ "justinrainbow/json-schema": ">=1.1.0",
+ "seld/jsonlint": "*",
"symfony/console": "dev-master",
"symfony/finder": "dev-master",
"symfony/process": "dev-master"
View
@@ -35,8 +35,7 @@
},
"version": {
"type": "string",
- "description": "Package version, see http://packagist.org/about for more info on valid schemes.",
- "required": true
+ "description": "Package version, see http://packagist.org/about for more info on valid schemes."
},
"time": {
"type": "string",
@@ -53,7 +53,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
}
try {
- JsonFile::parseJson(file_get_contents($file));
+ JsonFile::parseJson(file_get_contents($file), true);
} catch (\Exception $e) {
$output->writeln('<error>'.$e->getMessage().'</error>');
return 1;
@@ -128,4 +128,4 @@ protected function getDefaultHelperSet()
return $helperSet;
}
-}
+}
View
@@ -54,7 +54,7 @@ public function createComposer(IOInterface $io, $composerFile = null)
'vendor-dir' => 'vendor',
);
- $packageConfig = $file->read();
+ $packageConfig = $file->read(true);
if (isset($packageConfig['config']) && is_array($packageConfig['config'])) {
$packageConfig['config'] = array_merge($composerConfig, $packageConfig['config']);
@@ -14,6 +14,8 @@
use Composer\Repository\RepositoryManager;
use Composer\Composer;
+use JsonSchema\Validator;
+use Seld\JsonLint\JsonParser;
use Composer\Util\StreamContextFactory;
if (!defined('JSON_UNESCAPED_SLASHES')) {
@@ -68,7 +70,7 @@ public function exists()
*
* @return array
*/
- public function read()
+ public function read($validate = false)
{
$ctx = StreamContextFactory::getContext(array(
'http' => array(
@@ -80,7 +82,7 @@ public function read()
throw new \RuntimeException('Could not read '.$this->path.', you are probably offline');
}
- return static::parseJson($json);
+ return static::parseJson($json, $validate);
}
/**
@@ -215,59 +217,64 @@ static public function encode($data, $options = 448)
/**
* Parses json string and returns hash.
*
- * @param string $json json string
+ * @param string $json json string
+ * @param boolean $validateSchema wether to validate the json schema
*
* @return mixed
*/
- static public function parseJson($json)
+ public static function parseJson($json, $validateSchema=false)
+ {
+ $data = static::validateSyntax($json);
+
+ if ($validateSchema) {
+ static::validateSchema($json);
+ }
+
+ return $data;
+ }
+
+ /**
+ * validates a composer.json against the schema
+ *
+ * @param string $json
+ * @return boolean
+ * @throws \UnexpectedValueException
+ */
+ public static function validateSchema($json)
{
- $data = json_decode($json, true);
-
- if (null === $data && 'null' !== strtolower($json)) {
- switch (json_last_error()) {
- case JSON_ERROR_NONE:
- $msg = 'No error has occurred, is your composer.json file empty?';
- break;
- case JSON_ERROR_DEPTH:
- $msg = 'The maximum stack depth has been exceeded';
- break;
- case JSON_ERROR_STATE_MISMATCH:
- $msg = 'Invalid or malformed JSON';
- break;
- case JSON_ERROR_CTRL_CHAR:
- $msg = 'Control character error, possibly incorrectly encoded';
- break;
- case JSON_ERROR_SYNTAX:
- $msg = 'Syntax error';
- $charOffset = 0;
- if (preg_match('#["}\]]\s*(,)\s*[}\]]#', $json, $match, PREG_OFFSET_CAPTURE)) {
- $msg .= ', extra comma';
- } elseif (preg_match('#((?<=[^\\\\])\\\\(?!["\\\\/bfnrt]|u[a-f0-9]{4}))#i', $json, $match, PREG_OFFSET_CAPTURE)) {
- $msg .= ', unescaped backslash (\\)';
- } elseif (preg_match('#(["}\]])(?: *\r?\n *)+"#', $json, $match, PREG_OFFSET_CAPTURE)) {
- $msg .= ', missing comma';
- $charOffset = 1;
- } elseif (preg_match('#^ *([a-z0-9_-]+) *:#mi', $json, $match, PREG_OFFSET_CAPTURE)) {
- $msg .= ', you must use double quotes (") around keys';
- } elseif (preg_match('#(\'.+?\' *:|: *\'.+?\')#', $json, $match, PREG_OFFSET_CAPTURE)) {
- $msg .= ', use double quotes (") instead of single quotes (\')';
- } elseif (preg_match('#(\[".*?":.*?\])#', $json, $match, PREG_OFFSET_CAPTURE)) {
- $msg .= ', you must use the hash syntax (e.g. {"foo": "bar"}) instead of array syntax (e.g. ["foo", "bar"])';
- } elseif (preg_match('#".*?"( *["{\[])#', $json, $match, PREG_OFFSET_CAPTURE)) {
- $msg .= ', missing colon';
- }
- if (isset($match[1][1])) {
- $preError = substr($json, 0, $match[1][1]);
- $msg .= ' on line '.(substr_count($preError, "\n")+1).', char '.abs(strrpos($preError, "\n") - strlen($preError) - $charOffset);
- }
- break;
- case JSON_ERROR_UTF8:
- $msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
- break;
+ $data = json_decode($json);
+ $schema = json_decode(file_get_contents(__DIR__ . '/../../../res/composer-schema.json'));
+
+ $validator = new Validator();
+
+ $validator->check($data, $schema);
+
+ if (!$validator->isValid()) {
+ $msg = "\n";
+ foreach ((array) $validator->getErrors() as $error) {
+ $msg .= ($error['property'] ? $error['property'].' : ' : '').$error['message']."\n";
}
- throw new \UnexpectedValueException('JSON Parse Error: '.$msg);
+
+ throw new \UnexpectedValueException('Your composer.json did not validate against the schema. The following mistakes were found:'.$msg);
}
+ }
- return $data;
+ /**
+ * validates the json syntax
+ *
+ * @param string $json
+ * @return array
+ * @throws \UnexpectedValueException
+ */
+ public static function validateSyntax($json)
+ {
+ $parser = new JsonParser();
+ $result = $parser->lint($json);
+
+ if (null === $result) {
+ return json_decode($json, true);
+ }
+
+ throw $result;
}
}
Oops, something went wrong.

0 comments on commit 6929c42

Please sign in to comment.