diff --git a/LICENSE b/LICENSE index 3d860d9..88bfeb2 100644 --- a/LICENSE +++ b/LICENSE @@ -178,3 +178,28 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +------------------------ +austinhyde - IniParser + +The MIT License (MIT) +Copyright (c) 2013 Austin Hyde + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/Makefile b/Makefile index a4e4801..a8fec32 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ autoload: make src/ncc/ThirdParty/Symfony/Process/autoload_spl.php make src/ncc/ThirdParty/Symfony/Uid/autoload_spl.php make src/ncc/ThirdParty/Symfony/Filesystem/autoload_spl.php + make src/ncc/ThirdParty/austinhyde/IniParser/autoload_spl.php make src/ncc/autoload_spl.php cp src/autoload/autoload.php src/ncc/autoload.php @@ -33,6 +34,10 @@ src/ncc/ThirdParty/Symfony/Filesystem/autoload_spl.php: /usr/bin/env phpab --output src/ncc/ThirdParty/Symfony/Filesystem/autoload_spl.php \ src/ncc/ThirdParty/Symfony/Filesystem +src/ncc/ThirdParty/austinhyde/IniParser/autoload_spl.php: + /usr/bin/env phpab --output src/ncc/ThirdParty/austinhyde/IniParser/autoload_spl.php \ + src/ncc/ThirdParty/austinhyde/IniParser + src/ncc/autoload_spl.php: /usr/bin/env phpab --output src/ncc/autoload_spl.php \ src/ncc/Abstracts \ @@ -70,4 +75,5 @@ clean: rm -f src/ncc/ThirdParty/Symfony/polyfill-mbstring/autoload_spl.php rm -f src/ncc/ThirdParty/Symfony/Process/autoload_spl.php rm -f src/ncc/ThirdParty/Symfony/Uid/autoload_spl.php - rm -f src/ncc/ThirdParty/Symfony/Filesystem/autoload_spl.php \ No newline at end of file + rm -f src/ncc/ThirdParty/Symfony/Filesystem/autoload_spl.php + rm -f src/ncc/ThirdParty/austinhyde/IniParser/autoload_spl.php \ No newline at end of file diff --git a/README.md b/README.md index 131e4fe..acbd36c 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ a PPM extension may be built in the future to allow for backwards compatibility. - Copyright (c) 2022-2022, Nosial - All Rights Reserved - Copyright (c) 2004-2022, Fabien Potencier - Copyright (c) 2010, dealnews.com, Inc. All rights reserved. + - Copyright (c) 2013 Austin Hyde # Licenses diff --git a/src/autoload/autoload.php b/src/autoload/autoload.php index a1d00d1..ef852e0 100644 --- a/src/autoload/autoload.php +++ b/src/autoload/autoload.php @@ -21,6 +21,7 @@ $third_party_path . 'Symfony' . DIRECTORY_SEPARATOR . 'Process' . DIRECTORY_SEPARATOR . 'autoload_spl.php', $third_party_path . 'Symfony' . DIRECTORY_SEPARATOR . 'Uid' . DIRECTORY_SEPARATOR . 'autoload_spl.php', $third_party_path . 'Symfony' . DIRECTORY_SEPARATOR . 'Filesystem' . DIRECTORY_SEPARATOR . 'autoload_spl.php', + $third_party_path . 'austinhyde' . DIRECTORY_SEPARATOR . 'IniParser' . DIRECTORY_SEPARATOR . 'autoload_spl.php', ]; foreach($target_files as $file) diff --git a/src/config/ncc.ini b/src/config/ncc.ini index 4c40c2b..f3b7d36 100644 --- a/src/config/ncc.ini +++ b/src/config/ncc.ini @@ -1,42 +1,42 @@ [ncc] -# The default data directory that is used by NCC to store packages, -# cache, configuration files and other generated files. This includes -# data stored by packages using the NCC storage API. +; The default data directory that is used by NCC to store packages, +; cache, configuration files and other generated files. This includes +; data stored by packages using the NCC storage API. data_directory=/var/ncc [php] -# Configuration section for the PHP configuration that NCC will use to run +; Configuration section for the PHP configuration that NCC will use to run -# The main executable path for PHP that NCC should use +; The main executable path for PHP that NCC should use executable_path=/usr/bin/php -# Enables/Disables the environment configuration feature -# Allowing packages to install environment configurations to NCC -# that can be loaded during runtime using the NCC API -# -# If disabled packages may break if they depend on this feature. -# -# Leaving this enabled while installing and using unknown packages -# without reviewing their source code could lead to potential security -# issues/backdoors, use this feature for containerized environments +; Enables/Disables the environment configuration feature +; Allowing packages to install environment configurations to NCC +; that can be loaded during runtime using the NCC API +; +; If disabled packages may break if they depend on this feature. +; +; Leaving this enabled while installing and using unknown packages +; without reviewing their source code could lead to potential security +; issues/backdoors, use this feature for containerized environments enable_environment_configurations=False -# Enables/Disables the injection of NCC's include path -# during the initialization phase allowing you to import -# packages using the `import()` function and other ncc -# API Functions without needing to require NCC's autoloader -# -# This feature is highly recommended to be enabled +; Enables/Disables the injection of NCC's include path +; during the initialization phase allowing you to import +; packages using the `import()` function and other ncc +; API Functions without needing to require NCC's autoloader +; +; This feature is highly recommended to be enabled enable_include_path=True [git] executable_path=/usr/bin/git [composer] -# When enabled, NCC will use it's builtin version of composer -# to execute composer tasks, if disabled it will fallback to -# the `executable_path` option and attempt to use that specified -# location of composer +; When enabled, NCC will use it's builtin version of composer +; to execute composer tasks, if disabled it will fallback to +; the `executable_path` option and attempt to use that specified +; location of composer enable_internal_composer=True executable_path=/home/user/composer.phar \ No newline at end of file diff --git a/src/ncc/Managers/ConfigurationManager.php b/src/ncc/Managers/ConfigurationManager.php new file mode 100644 index 0000000..8446056 --- /dev/null +++ b/src/ncc/Managers/ConfigurationManager.php @@ -0,0 +1,16 @@ +Package = $package; + } + } \ No newline at end of file diff --git a/src/ncc/ThirdParty/austinhyde/IniParser/IniParser.php b/src/ncc/ThirdParty/austinhyde/IniParser/IniParser.php new file mode 100644 index 0000000..6511c8a --- /dev/null +++ b/src/ncc/ThirdParty/austinhyde/IniParser/IniParser.php @@ -0,0 +1,282 @@ + + */ +class IniParser +{ + + /** + * Filename of our .ini file. + * @var string + */ + protected $file; + + /** + * Enable/disable property nesting feature + * @var boolean + */ + public $property_nesting = true; + + /** + * Use ArrayObject to allow array work as object (true) or use native arrays (false) + * @var boolean + */ + public $use_array_object = true; + + /** + * Include original sections (pre-inherit names) on the final output + * @var boolean + */ + public $include_original_sections = false; + + /** + * Disable array literal parsing + */ + const NO_PARSE = 0; + + /** + * Parse simple arrays using regex (ex: [a,b,c,...]) + */ + const PARSE_SIMPLE = 1; + + /** + * Parse array literals using JSON, allowing advanced features like + * dictionaries, array nesting, etc. + */ + const PARSE_JSON = 2; + + /** + * Array literals parse mode + * @var int + */ + public $array_literals_behavior = self::PARSE_SIMPLE; + + /** + * @param string $file + * + * @return IniParser + */ + public function __construct($file = null) + { + if ($file !== null) { + $this->setFile($file); + } + } + + /** + * Parses an INI file + * + * @param string $file + * @return array + */ + public function parse($file = null) + { + if ($file !== null) { + $this->setFile($file); + } + if (empty($this->file)) { + throw new LogicException("Need a file to parse."); + } + + $simple_parsed = parse_ini_file($this->file, true); + $inheritance_parsed = $this->parseSections($simple_parsed); + return $this->parseKeys($inheritance_parsed); + } + + /** + * Parses a string with INI contents + * + * @param string $src + * + * @return array + */ + public function process($src) + { + $simple_parsed = parse_ini_string($src, true); + $inheritance_parsed = $this->parseSections($simple_parsed); + return $this->parseKeys($inheritance_parsed); + } + + /** + * @param string $file + * + * @return IniParser + * @throws InvalidArgumentException + */ + public function setFile($file) + { + if (!file_exists($file) || !is_readable($file)) { + throw new InvalidArgumentException("The file '{$file}' cannot be opened."); + } + $this->file = $file; + return $this; + } + + /** + * Parse sections and inheritance. + * @param array $simple_parsed + * @return array Parsed sections + */ + private function parseSections(array $simple_parsed) + { + // do an initial pass to gather section names + $sections = array(); + $globals = array(); + foreach ($simple_parsed as $k => $v) { + if (is_array($v)) { + // $k is a section name + $sections[$k] = $v; + } else { + $globals[$k] = $v; + } + } + + // now for each section, see if it uses inheritance + $output_sections = array(); + foreach ($sections as $k => $v) { + $sects = array_map('trim', array_reverse(explode(':', $k))); + $root = array_pop($sects); + $arr = $v; + foreach ($sects as $s) { + if ($s === '^') { + $arr = array_merge($globals, $arr); + } elseif (array_key_exists($s, $output_sections)) { + $arr = array_merge($output_sections[$s], $arr); + } elseif (array_key_exists($s, $sections)) { + $arr = array_merge($sections[$s], $arr); + } else { + throw new UnexpectedValueException("IniParser: In file '{$this->file}', section '{$root}': Cannot inherit from unknown section '{$s}'"); + } + } + + if ($this->include_original_sections) { + $output_sections[$k] = $v; + } + $output_sections[$root] = $arr; + } + + + return $globals + $output_sections; + } + + /** + * @param array $arr + * + * @return array + */ + private function parseKeys(array $arr) + { + $output = $this->getArrayValue(); + $append_regex = '/\s*\+\s*$/'; + foreach ($arr as $k => $v) { + if (is_array($v) && FALSE === strpos($k, '.')) { + // this element represents a section; recursively parse the value + $output[$k] = $this->parseKeys($v); + } else { + // if the key ends in a +, it means we should append to the previous value, if applicable + $append = false; + if (preg_match($append_regex, $k)) { + $k = preg_replace($append_regex, '', $k); + $append = true; + } + + // transform "a.b.c = x" into $output[a][b][c] = x + $current = &$output; + + $path = $this->property_nesting ? explode('.', $k) : array($k); + while (($current_key = array_shift($path)) !== null) { + if ('string' === gettype($current)) { + $current = array($current); + } + + if (!array_key_exists($current_key, $current)) { + if (!empty($path)) { + $current[$current_key] = $this->getArrayValue(); + } else { + $current[$current_key] = null; + } + } + $current = &$current[$current_key]; + } + + // parse value + $value = $v; + if (!is_array($v)) { + $value = $this->parseValue($v); + } + + if ($append && $current !== null) { + if (is_array($value)) { + if (!is_array($current)) { + throw new LogicException("Cannot append array to inherited value '{$k}'"); + } + $value = array_merge($current, $value); + } else { + $value = $current . $value; + } + } + + $current = $value; + } + } + + return $output; + } + + /** + * Parses and formats the value in a key-value pair + * + * @param string $value + * + * @return mixed + */ + protected function parseValue($value) + { + switch ($this->array_literals_behavior) { + case self::PARSE_JSON: + if (in_array(substr($value, 0, 1), array('[', '{')) && in_array(substr($value, -1), array(']', '}'))) { + if (defined('JSON_BIGINT_AS_STRING')) { + $output = json_decode($value, true, 512, JSON_BIGINT_AS_STRING); + } else { + $output = json_decode($value, true); + } + + if ($output !== NULL) { + return $output; + } + } + // fallthrough + // try regex parser for simple estructures not JSON-compatible (ex: colors = [blue, green, red]) + case self::PARSE_SIMPLE: + // if the value looks like [a,b,c,...], interpret as array + if (preg_match('/^\[\s*.*?(?:\s*,\s*.*?)*\s*\]$/', trim($value))) { + return array_map('trim', explode(',', trim(trim($value), '[]'))); + } + break; + } + return $value; + } + + protected function getArrayValue($array = array()) + { + if ($this->use_array_object) { + return new ArrayObject($array, ArrayObject::ARRAY_AS_PROPS); + } else { + return $array; + } + } + +} diff --git a/src/ncc/ThirdParty/austinhyde/IniParser/LICENSE b/src/ncc/ThirdParty/austinhyde/IniParser/LICENSE new file mode 100644 index 0000000..463eabf --- /dev/null +++ b/src/ncc/ThirdParty/austinhyde/IniParser/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013 Austin Hyde + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/src/ncc/ThirdParty/austinhyde/IniParser/README.markdown b/src/ncc/ThirdParty/austinhyde/IniParser/README.markdown new file mode 100644 index 0000000..ecbb4bd --- /dev/null +++ b/src/ncc/ThirdParty/austinhyde/IniParser/README.markdown @@ -0,0 +1,247 @@ +# IniParser + +[![Build Status](https://secure.travis-ci.org/austinhyde/IniParser.png?branch=master)](http://travis-ci.org/austinhyde/IniParser) + +IniParser is a simple parser for complex INI files, providing a number of extra syntactic features to the built-in INI parsing functions, including section inheritance, property nesting, and array literals. + +**IMPORTANT:** IniParser should be considered beta-quality, and there may still be bugs. Feel free to open an issue or submit a pull request, and I'll take a look at it! + +## Installing by [Composer](https://getcomposer.org) + +Set your `composer.json` file to have : + +```json +{ + "require": { + "austinhyde/iniparser": "dev-master" + } +} +``` + +Then install the dependencies : + +```shell +composer install +``` + +## An Example + +Standard INI files look like this: + + key = value + another_key = another value + + [section_name] + a_sub_key = yet another value + +And when parsed with PHP's built-in `parse_ini_string()` or `parse_ini_file()`, looks like + +```php +array( + 'key' => 'value', + 'another_key' => 'another value', + 'section_name' => array( + 'a_sub_key' => 'yet another value' + ) +) +``` + +This is great when you just want a simple configuration file, but here is a super-charged INI file that you might find in the wild: + + environment = testing + + [testing] + debug = true + database.connection = "mysql:host=127.0.0.1" + database.name = test + database.username = + database.password = + secrets = [1,2,3] + + [staging : testing] + database.name = stage + database.username = staging + database.password = 12345 + + [production : staging] + debug = false; + database.name = production + database.username = root + +And when parsed with IniParser: + + $parser = new \IniParser('sample.ini'); + $config = $parser->parse(); + +You get the following structure: + +```php +array( + 'environment' => 'testing', + 'testing' => array( + 'debug' => '1', + 'database' => array( + 'connection' => 'mysql:host=127.0.0.1', + 'name' => 'test', + 'username' => '', + 'password' => '' + ), + 'secrets' => array('1','2','3') + ), + 'staging' => array( + 'debug' => '1', + 'database' => array( + 'connection' => 'mysql:host=127.0.0.1', + 'name' => 'stage', + 'username' => 'staging', + 'password' => '12345' + ), + 'secrets' => array('1','2','3') + ), + 'production' => array( + 'debug' => '', + 'database' => array( + 'connection' => 'mysql:host=127.0.0.1', + 'name' => 'production', + 'username' => 'root', + 'password' => '12345' + ), + 'secrets' => array('1','2','3') + ) +) +``` + +## Supported Features + +### Array Literals + +You can directly create arrays using the syntax `[a, b, c]` on the right hand side of an assignment. For example: + + colors = [blue, green, red] + +**NOTE:** At the moment, quoted strings inside array literals have undefined behavior. + +### Dictionaries and complex structures + +Besides arrays, you can create dictionaries and more complex structures using JSON syntax. For example, you can use: + + people = '{ + "boss": { + "name": "John", + "age": 42 + }, + "staff": [ + { + "name": "Mark", + "age": 35 + }, + { + "name": "Bill", + "age": 44 + } + ] + }' + +This turns into an array like: + +```php +array( + 'boss' => array( + 'name' => 'John', + 'age' => 42 + ), + 'staff' => array( + array ( + 'name' => 'Mark', + 'age' => 35, + ), + array ( + 'name' => 'Bill', + 'age' => 44, + ), + ), +) +``` + +**NOTE:** Remember to wrap the JSON strings in single quotes for a correct analysis. The JSON names must be enclosed in double quotes and trailing commas are not allowed. + +### Property Nesting + +IniParser allows you to treat properties as associative arrays: + + person.age = 42 + person.name.first = John + person.name.last = Doe + +This turns into an array like: + +```php +array ( + 'person' => array ( + 'age' => 42, + 'name' => array ( + 'first' => 'John', + 'last' => 'Doe' + ) + ) +) +``` + +### Section Inheritance + +Keeping to the DRY principle, IniParser allows you to "inherit" from other sections (similar to OOP inheritance), meaning you don't have to continually re-define the same properties over and over again. As you can see in the example above, "production" inherits from "staging", which in turn inherits from "testing". + +You can even inherit from multiple parents, as in `[child : p1 : p2 : p3]`. The properties of each parent are merged into the child from left to right, so that the properties in `p1` are overridden by those in `p2`, then by `p3`, then by those in `child` on top of that. + +During the inheritance process, if a key ends in a `+`, the merge behavior changes from overwriting the parent value to prepending the parent value (or appending the child value - same thing). So the example file + + [parent] + arr = [a,b,c] + val = foo + + [child : parent] + arr += [x,y,z] + val += bar + +would be parsed into the following: + +```php +array( + 'parent' => array( + 'arr' => array('a','b','c'), + 'val' => 'foo' + ), + 'child' => array( + 'arr' => array('a','b','c','x','y','z'), + 'val' => 'foobar' + ) +) +``` + +*If you can think of a more useful operation than concatenation for non-array types, please open an issue* + +Finally, it is possible to inherit from the special `^` section, representing the top-level or global properties: + + foo = bar + + [sect : ^] + +Parses to: + +```php +array ( + 'foo' => 'bar', + 'sect' => array ( + 'foo' => 'bar' + ) +) +``` + +### ArrayObject + +As an added bonus, IniParser also allows you to access the values OO-style: + +```php +echo $config->production->database->connection; // output: mysql:host=127.0.0.1 +echo $config->staging->debug; // output: 1 +```