Added Symfony\Yaml, improved installer and Makefile and updated .gitignore
This commit is contained in:
parent
61ea95d95c
commit
5667ae25c5
30 changed files with 3514 additions and 637 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -11,5 +11,6 @@ src/ncc/ThirdParty/Symfony/polyfill-mbstring/autoload_spl.php
|
|||
src/ncc/ThirdParty/Symfony/Process/autoload_spl.php
|
||||
src/ncc/ThirdParty/Symfony/Uid/autoload_spl.php
|
||||
src/ncc/ThirdParty/Symfony/Filesystem/autoload_spl.php
|
||||
src/ncc/ThirdParty/Symfony/Yaml/autoload_spl.php
|
||||
src/ncc/autoload_spl.php
|
||||
src/ncc/autoload.php
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
|
@ -0,0 +1,5 @@
|
|||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||
</state>
|
||||
</component>
|
15
LICENSE
15
LICENSE
|
@ -181,20 +181,19 @@ THE SOFTWARE.
|
|||
|
||||
|
||||
------------------------
|
||||
austinhyde - IniParser
|
||||
Symfony - Yaml
|
||||
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2013 Austin Hyde
|
||||
Copyright (c) 2004-2022 Fabien Potencier
|
||||
|
||||
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:
|
||||
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 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,
|
||||
|
@ -202,4 +201,4 @@ 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.
|
||||
THE SOFTWARE.
|
||||
|
|
13
Makefile
13
Makefile
|
@ -6,7 +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/ThirdParty/Symfony/Yaml/autoload_spl.php
|
||||
make src/ncc/autoload_spl.php
|
||||
cp src/autoload/autoload.php src/ncc/autoload.php
|
||||
|
||||
|
@ -34,9 +34,9 @@ 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/ThirdParty/Symfony/Yaml/autoload_spl.php:
|
||||
/usr/bin/env phpab --output src/ncc/ThirdParty/Symfony/Yaml/autoload_spl.php \
|
||||
src/ncc/ThirdParty/Symfony/Yaml
|
||||
|
||||
src/ncc/autoload_spl.php:
|
||||
/usr/bin/env phpab --output src/ncc/autoload_spl.php \
|
||||
|
@ -52,11 +52,12 @@ src/ncc/autoload_spl.php:
|
|||
src/ncc/ncc.php
|
||||
|
||||
redist: autoload
|
||||
rm -rf build
|
||||
rm -rf build/src
|
||||
mkdir build build/src
|
||||
cp -rf src/ncc/* build/src
|
||||
cp src/installer/installer build/src/INSTALL
|
||||
cp src/installer/ncc.sh build/src/ncc.sh
|
||||
cp src/config/ncc.yaml build/src/default_config.yaml;
|
||||
cp src/installer/extension build/src/extension
|
||||
chmod +x build/src/INSTALL
|
||||
cp LICENSE build/src/LICENSE
|
||||
|
@ -76,4 +77,4 @@ clean:
|
|||
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
|
||||
rm -f src/ncc/ThirdParty/austinhyde/IniParser/autoload_spl.php
|
||||
rm -f src/ncc/ThirdParty/Symfony/Yaml/autoload_spl.php
|
||||
|
|
|
@ -21,7 +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',
|
||||
$third_party_path . 'Symfony' . DIRECTORY_SEPARATOR . 'Yaml' . DIRECTORY_SEPARATOR . 'autoload_spl.php',
|
||||
];
|
||||
|
||||
foreach($target_files as $file)
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
[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.
|
||||
data_directory=/var/ncc
|
||||
|
||||
|
||||
[php]
|
||||
; Configuration section for the PHP configuration that NCC will use to run
|
||||
|
||||
; 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
|
||||
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
|
||||
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
|
||||
enable_internal_composer=True
|
||||
executable_path=/home/user/composer.phar
|
41
src/config/ncc.yaml
Normal file
41
src/config/ncc.yaml
Normal file
|
@ -0,0 +1,41 @@
|
|||
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.
|
||||
data_directory: "/var/ncc"
|
||||
|
||||
php:
|
||||
# Configuration section for the PHP configuration that NCC will use to run
|
||||
|
||||
# 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
|
||||
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
|
||||
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
|
||||
enable_internal_composer: true
|
||||
executable_path: "/home/user/composer.phar"
|
|
@ -33,8 +33,9 @@
|
|||
$excluded_files = [
|
||||
'hash_check.php',
|
||||
'generate_build_files.php',
|
||||
'default_config.yaml',
|
||||
'installer',
|
||||
'checksum.bin'.
|
||||
'checksum.bin',
|
||||
'build_files',
|
||||
'ncc.sh',
|
||||
'extension'
|
||||
|
@ -50,7 +51,7 @@
|
|||
$build_files_content = [];
|
||||
foreach(scanContents(__DIR__) as $path)
|
||||
{
|
||||
if(!in_array($path, $excluded_files))
|
||||
if(!in_array($path, $excluded_files, true))
|
||||
{
|
||||
$build_files_content[] = $path;
|
||||
}
|
||||
|
|
|
@ -19,17 +19,19 @@
|
|||
use ncc\Exceptions\InvalidScopeException;
|
||||
use ncc\Managers\CredentialManager;
|
||||
use ncc\ncc;
|
||||
use ncc\Objects\CliHelpSection;
|
||||
use ncc\ThirdParty\Symfony\Filesystem\Exception\IOException;
|
||||
use ncc\Objects\CliHelpSection;
|
||||
use ncc\ThirdParty\Symfony\Filesystem\Exception\IOException;
|
||||
use ncc\ThirdParty\Symfony\Filesystem\Filesystem;
|
||||
use ncc\ThirdParty\Symfony\Process\Exception\ProcessFailedException;
|
||||
use ncc\ThirdParty\Symfony\process\PhpExecutableFinder;
|
||||
use ncc\ThirdParty\Symfony\Process\ExecutableFinder;
|
||||
use ncc\ThirdParty\Symfony\process\PhpExecutableFinder;
|
||||
use ncc\ThirdParty\Symfony\Process\Process;
|
||||
use ncc\ThirdParty\Symfony\Yaml\Yaml;
|
||||
use ncc\Utilities\Console;
|
||||
use ncc\Utilities\Functions;
|
||||
use ncc\Utilities\PathFinder;
|
||||
use ncc\Utilities\Resolver;
|
||||
use ncc\Utilities\Validate;
|
||||
use ncc\Utilities\Functions;
|
||||
use ncc\Utilities\PathFinder;
|
||||
use ncc\Utilities\Resolver;
|
||||
use ncc\Utilities\Validate;
|
||||
use ncc\ZiProto\ZiProto;
|
||||
|
||||
# Global Variables
|
||||
|
@ -41,6 +43,34 @@ use ncc\Utilities\Validate;
|
|||
$NCC_PHP_EXECUTABLE=null;
|
||||
$NCC_FILESYSTEM=null;
|
||||
|
||||
/**
|
||||
* A getParameter function to avoid code redundancy (Type-Safe)
|
||||
*
|
||||
* @param array|null $args
|
||||
* @param string $option
|
||||
* @param bool $require_content
|
||||
* @return string|null
|
||||
*/
|
||||
function getParameter(?array $args, string $option, bool $require_content=true): ?string
|
||||
{
|
||||
if($args == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if(!isset($args[$option]))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if($require_content && ($args[$option] == null || strlen((string)$args[$option] == 0)))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return $args[$option];
|
||||
}
|
||||
|
||||
// Require NCC
|
||||
if(!file_exists($NCC_AUTOLOAD))
|
||||
{
|
||||
|
@ -69,6 +99,8 @@ use ncc\Utilities\Validate;
|
|||
$NCC_ARGS = Resolver::parseArguments(implode(' ', $argv));
|
||||
}
|
||||
|
||||
$NCC_AUTO_MODE = ($NCC_ARGS !== null && isset($NCC_ARGS['auto']));
|
||||
|
||||
if(isset($NCC_ARGS['help']))
|
||||
{
|
||||
$options = [
|
||||
|
@ -131,6 +163,7 @@ use ncc\Utilities\Validate;
|
|||
// Find the PHP executable
|
||||
$executable_finder = new PhpExecutableFinder();
|
||||
$NCC_PHP_EXECUTABLE = $executable_finder->find();
|
||||
$NCC_EXECUTABLE_FINDER = new ExecutableFinder();
|
||||
if(!$NCC_PHP_EXECUTABLE)
|
||||
{
|
||||
Console::outError('Cannot find PHP executable path');
|
||||
|
@ -142,6 +175,7 @@ use ncc\Utilities\Validate;
|
|||
__DIR__ . DIRECTORY_SEPARATOR . 'LICENSE',
|
||||
__DIR__ . DIRECTORY_SEPARATOR . 'build_files',
|
||||
__DIR__ . DIRECTORY_SEPARATOR . 'ncc.sh',
|
||||
__DIR__ . DIRECTORY_SEPARATOR . 'default_config.yaml',
|
||||
];
|
||||
foreach($required_files as $path)
|
||||
{
|
||||
|
@ -242,65 +276,124 @@ use ncc\Utilities\Validate;
|
|||
}
|
||||
|
||||
// Determine the installation path
|
||||
// TODO: Add the ability to change the data path as well
|
||||
if($NCC_ARGS == null && !isset($NCC_ARGS['auto']))
|
||||
$skip_prompt = false;
|
||||
$install_dir_arg = getParameter($NCC_ARGS, 'install-dir');
|
||||
|
||||
// Check the arguments
|
||||
if($install_dir_arg !== null)
|
||||
{
|
||||
if(!Validate::unixFilepath($install_dir_arg))
|
||||
{
|
||||
Console::outError('The given file path is not valid');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(file_exists($install_dir_arg . DIRECTORY_SEPARATOR . 'ncc'))
|
||||
{
|
||||
Console::out('NCC Seems to already be installed, the installer will repair/upgrade your current install');
|
||||
$NCC_INSTALL_PATH = $install_dir_arg;
|
||||
$skip_prompt = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console::outError('The given directory already exists, it must be deleted before proceeding');
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if(!$NCC_AUTO_MODE && !$skip_prompt)
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
$user_input = null;
|
||||
$user_input = Console::getInput("Installation Path (Default: $NCC_INSTALL_PATH): ");
|
||||
if(strlen($user_input) > 0)
|
||||
if(strlen($user_input) > 0 && file_exists($user_input) && Validate::unixFilepath($user_input))
|
||||
{
|
||||
if(file_exists($user_input))
|
||||
if(file_exists($user_input . DIRECTORY_SEPARATOR . 'ncc'))
|
||||
{
|
||||
if(file_exists($user_input . DIRECTORY_SEPARATOR . 'ncc'))
|
||||
{
|
||||
Console::out('NCC Seems to already be installed, the installer will repair/upgrade your current install');
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console::outError('The given directory already exists, it must be deleted before proceeding');
|
||||
}
|
||||
$NCC_INSTALL_PATH = $user_input;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
Console::outError('The given directory already exists, it must be deleted before proceeding');
|
||||
}
|
||||
}
|
||||
elseif(strlen($user_input) > 0)
|
||||
{
|
||||
Console::outError('The given file path is not valid');
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
|
||||
// Determine the data path
|
||||
$skip_prompt = false;
|
||||
$data_dir_arg = getParameter($NCC_ARGS, 'data-dir');
|
||||
|
||||
// Check the arguments
|
||||
if($data_dir_arg !== null)
|
||||
{
|
||||
if(strlen($NCC_ARGS['install-dir']) > 0)
|
||||
if(!Validate::unixFilepath($data_dir_arg))
|
||||
{
|
||||
if(file_exists($NCC_ARGS['install-dir']))
|
||||
Console::outError('The given file path \''. $data_dir_arg . '\' is not valid');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(file_exists($data_dir_arg . DIRECTORY_SEPARATOR . 'package.lck'))
|
||||
{
|
||||
$NCC_DATA_PATH = $data_dir_arg;
|
||||
$skip_prompt = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console::outError('The given directory \'' . $data_dir_arg . '\' already exists, it must be deleted before proceeding');
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Proceed with prompt if not in auto mode and argument was met
|
||||
if(!$NCC_AUTO_MODE && !$skip_prompt)
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
$user_input = null;
|
||||
$user_input = Console::getInput("Data Path (Default: $NCC_DATA_PATH): ");
|
||||
if(strlen($user_input) > 0 && file_exists($user_input) && Validate::unixFilepath($user_input))
|
||||
{
|
||||
if(file_exists($NCC_ARGS['install-dir'] . DIRECTORY_SEPARATOR . 'ncc'))
|
||||
if(file_exists($user_input . DIRECTORY_SEPARATOR . 'package.lck'))
|
||||
{
|
||||
Console::out('NCC Seems to already be installed, the installer will repair/upgrade your current install');
|
||||
$NCC_DATA_PATH = $user_input;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console::outError('The given directory already exists, it must be deleted before proceeding');
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
elseif(strlen($user_input) > 0)
|
||||
{
|
||||
Console::outError('The given file path is not valid');
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ask to install composer if curl is available
|
||||
if($curl_available)
|
||||
{
|
||||
if($NCC_ARGS !== null && isset($NCC_ARGS['auto']) && isset($NCC_ARGS['install-composer']))
|
||||
if(getParameter($NCC_ARGS, 'install-composer') !== null)
|
||||
{
|
||||
$update_composer = true;
|
||||
}
|
||||
elseif(isset($NCC_ARGS['install-composer']))
|
||||
elseif(getParameter($NCC_ARGS, 'install-composer') !== null)
|
||||
{
|
||||
$update_composer = true;
|
||||
}
|
||||
|
@ -310,8 +403,12 @@ use ncc\Utilities\Validate;
|
|||
$update_composer = Console::getBooleanInput('Do you want to install composer for NCC? (Recommended)');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$update_composer = false;
|
||||
}
|
||||
|
||||
if($NCC_ARGS == null && !isset($NCC_ARGS['auto']))
|
||||
if(!$NCC_AUTO_MODE)
|
||||
{
|
||||
if(!Console::getBooleanInput('Do you want install NCC?'))
|
||||
{
|
||||
|
@ -320,6 +417,14 @@ use ncc\Utilities\Validate;
|
|||
}
|
||||
}
|
||||
|
||||
// Backup the configuration file
|
||||
$config_backup = null;
|
||||
if(file_exists($NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'ncc.yaml'))
|
||||
{
|
||||
Console::out('ncc.yaml will be updated');
|
||||
$config_backup = file_get_contents($NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'ncc.yaml');
|
||||
}
|
||||
|
||||
// Prepare installation
|
||||
if(file_exists($NCC_INSTALL_PATH))
|
||||
{
|
||||
|
@ -347,13 +452,9 @@ use ncc\Utilities\Validate;
|
|||
$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'ext',
|
||||
];
|
||||
|
||||
$NCC_FILESYSTEM->mkdir($required_dirs);
|
||||
foreach($required_dirs as $dir)
|
||||
{
|
||||
$NCC_FILESYSTEM->chmod([$dir], 0755);
|
||||
}
|
||||
$NCC_FILESYSTEM->chmod([$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'config'], 0755);
|
||||
$NCC_FILESYSTEM->chmod([$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'cache'], 0755);
|
||||
$NCC_FILESYSTEM->mkdir($required_dirs, 0755);
|
||||
$NCC_FILESYSTEM->chmod([$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'config'], 0777);
|
||||
$NCC_FILESYSTEM->chmod([$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'cache'], 0777);
|
||||
|
||||
// Install composer
|
||||
if($curl_available && $update_composer)
|
||||
|
@ -390,12 +491,20 @@ use ncc\Utilities\Validate;
|
|||
}
|
||||
catch(ProcessFailedException $e)
|
||||
{
|
||||
Console::outError('Cannot install composer, ' . $e->getMessage());
|
||||
Console::outError('Cannot install compos)er, ' . $e->getMessage());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Verify install
|
||||
if(!$NCC_FILESYSTEM->exists([$NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'composer.phar']))
|
||||
{
|
||||
Console::outError("The installation exited without any issues but composer doesn't seem to be installed correctly");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$NCC_FILESYSTEM->remove([$NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'composer-setup.php']);
|
||||
$NCC_FILESYSTEM->chmod([$NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'composer.phar'], 0755);
|
||||
|
||||
Console::out('Installed composer successfully');
|
||||
}
|
||||
|
||||
|
@ -499,5 +608,63 @@ use ncc\Utilities\Validate;
|
|||
}
|
||||
}
|
||||
|
||||
// Create/Update configuration file
|
||||
$config_obj = Yaml::parseFile(__DIR__ . DIRECTORY_SEPARATOR . 'default_config.yaml');
|
||||
|
||||
// Update the old configuration
|
||||
if($config_backup !== null)
|
||||
{
|
||||
$old_config_obj = Yaml::parse($config_backup);
|
||||
foreach($old_config_obj as $section => $value)
|
||||
{
|
||||
if(isset($config_obj[$section]))
|
||||
{
|
||||
foreach($value as $section_item)
|
||||
{
|
||||
if(!isset($config_obj[$section][$section_item]))
|
||||
{
|
||||
$config_obj[$section][$section_item] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$config_obj[$section] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Overwrite automatic values created by the installer
|
||||
$config_obj['ncc']['data_directory'] = $NCC_DATA_PATH;
|
||||
$config_obj['php']['executable_path'] = $NCC_PHP_EXECUTABLE;
|
||||
$config_obj['git']['executable_path'] = $NCC_EXECUTABLE_FINDER->find('git');
|
||||
$config_obj['composer']['executable_path'] = $NCC_EXECUTABLE_FINDER->find('composer');
|
||||
|
||||
if($config_obj['git']['executable_path'] == null)
|
||||
{
|
||||
Console::outWarning('Cannot locate the executable path for \'git\', run \'ncc config --git.executable_path="GIT_PATH_HERE"\' as root to update the path');
|
||||
}
|
||||
|
||||
if(!$update_composer)
|
||||
{
|
||||
Console::outWarning('Since composer is not installed alongside NCC, the installer will attempt to locate a install of composer on your system and configure NCC to use that');
|
||||
$config_obj['composer']['enable_internal_composer'] = false;
|
||||
if($config_obj['composer']['executable_path'] == null)
|
||||
{
|
||||
Console::outWarning('Cannot locate the executable path for \'composer\', run \'ncc config --composer.executable_path="composer.phar"\' as root to update the path');
|
||||
}
|
||||
}
|
||||
|
||||
if($config_backup == null)
|
||||
{
|
||||
Console::out('Generating ncc.yaml');
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Console::out('Updating ncc.yaml');
|
||||
}
|
||||
|
||||
file_put_contents($NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'ncc.yaml', Yaml::dump($config_obj));
|
||||
Console::out('NCC has been successfully installed');
|
||||
exit(0);
|
242
src/ncc/ThirdParty/Symfony/Yaml/CHANGELOG.md
vendored
Normal file
242
src/ncc/ThirdParty/Symfony/Yaml/CHANGELOG.md
vendored
Normal file
|
@ -0,0 +1,242 @@
|
|||
CHANGELOG
|
||||
=========
|
||||
|
||||
6.1
|
||||
---
|
||||
|
||||
* In cases where it will likely improve readability, strings containing single quotes will be double-quoted
|
||||
|
||||
5.4
|
||||
---
|
||||
|
||||
* Add new `lint:yaml dirname --exclude=/dirname/foo.yaml --exclude=/dirname/bar.yaml`
|
||||
option to exclude one or more specific files from multiple file list
|
||||
* Allow negatable for the parse tags option with `--no-parse-tags`
|
||||
|
||||
5.3
|
||||
---
|
||||
|
||||
* Added `github` format support & autodetection to render errors as annotations
|
||||
when running the YAML linter command in a Github Action environment.
|
||||
|
||||
5.1.0
|
||||
-----
|
||||
|
||||
* Added support for parsing numbers prefixed with `0o` as octal numbers.
|
||||
* Deprecated support for parsing numbers starting with `0` as octal numbers. They will be parsed as strings as of Symfony 6.0. Prefix numbers with `0o`
|
||||
so that they are parsed as octal numbers.
|
||||
|
||||
Before:
|
||||
|
||||
```yaml
|
||||
Yaml::parse('072');
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```yaml
|
||||
Yaml::parse('0o72');
|
||||
```
|
||||
|
||||
* Added `yaml-lint` binary.
|
||||
* Deprecated using the `!php/object` and `!php/const` tags without a value.
|
||||
|
||||
5.0.0
|
||||
-----
|
||||
|
||||
* Removed support for mappings inside multi-line strings.
|
||||
* removed support for implicit STDIN usage in the `lint:yaml` command, use `lint:yaml -` (append a dash) instead to make it explicit.
|
||||
|
||||
4.4.0
|
||||
-----
|
||||
|
||||
* Added support for parsing the inline notation spanning multiple lines.
|
||||
* Added support to dump `null` as `~` by using the `Yaml::DUMP_NULL_AS_TILDE` flag.
|
||||
* deprecated accepting STDIN implicitly when using the `lint:yaml` command, use `lint:yaml -` (append a dash) instead to make it explicit.
|
||||
|
||||
4.3.0
|
||||
-----
|
||||
|
||||
* Using a mapping inside a multi-line string is deprecated and will throw a `ParseException` in 5.0.
|
||||
|
||||
4.2.0
|
||||
-----
|
||||
|
||||
* added support for multiple files or directories in `LintCommand`
|
||||
|
||||
4.0.0
|
||||
-----
|
||||
|
||||
* The behavior of the non-specific tag `!` is changed and now forces
|
||||
non-evaluating your values.
|
||||
* complex mappings will throw a `ParseException`
|
||||
* support for the comma as a group separator for floats has been dropped, use
|
||||
the underscore instead
|
||||
* support for the `!!php/object` tag has been dropped, use the `!php/object`
|
||||
tag instead
|
||||
* duplicate mapping keys throw a `ParseException`
|
||||
* non-string mapping keys throw a `ParseException`, use the `Yaml::PARSE_KEYS_AS_STRINGS`
|
||||
flag to cast them to strings
|
||||
* `%` at the beginning of an unquoted string throw a `ParseException`
|
||||
* mappings with a colon (`:`) that is not followed by a whitespace throw a
|
||||
`ParseException`
|
||||
* the `Dumper::setIndentation()` method has been removed
|
||||
* being able to pass boolean options to the `Yaml::parse()`, `Yaml::dump()`,
|
||||
`Parser::parse()`, and `Dumper::dump()` methods to configure the behavior of
|
||||
the parser and dumper is no longer supported, pass bitmask flags instead
|
||||
* the constructor arguments of the `Parser` class have been removed
|
||||
* the `Inline` class is internal and no longer part of the BC promise
|
||||
* removed support for the `!str` tag, use the `!!str` tag instead
|
||||
* added support for tagged scalars.
|
||||
|
||||
```yml
|
||||
Yaml::parse('!foo bar', Yaml::PARSE_CUSTOM_TAGS);
|
||||
// returns TaggedValue('foo', 'bar');
|
||||
```
|
||||
|
||||
3.4.0
|
||||
-----
|
||||
|
||||
* added support for parsing YAML files using the `Yaml::parseFile()` or `Parser::parseFile()` method
|
||||
|
||||
* the `Dumper`, `Parser`, and `Yaml` classes are marked as final
|
||||
|
||||
* Deprecated the `!php/object:` tag which will be replaced by the
|
||||
`!php/object` tag (without the colon) in 4.0.
|
||||
|
||||
* Deprecated the `!php/const:` tag which will be replaced by the
|
||||
`!php/const` tag (without the colon) in 4.0.
|
||||
|
||||
* Support for the `!str` tag is deprecated, use the `!!str` tag instead.
|
||||
|
||||
* Deprecated using the non-specific tag `!` as its behavior will change in 4.0.
|
||||
It will force non-evaluating your values in 4.0. Use plain integers or `!!float` instead.
|
||||
|
||||
3.3.0
|
||||
-----
|
||||
|
||||
* Starting an unquoted string with a question mark followed by a space is
|
||||
deprecated and will throw a `ParseException` in Symfony 4.0.
|
||||
|
||||
* Deprecated support for implicitly parsing non-string mapping keys as strings.
|
||||
Mapping keys that are no strings will lead to a `ParseException` in Symfony
|
||||
4.0. Use quotes to opt-in for keys to be parsed as strings.
|
||||
|
||||
Before:
|
||||
|
||||
```php
|
||||
$yaml = <<<YAML
|
||||
null: null key
|
||||
true: boolean true
|
||||
2.0: float key
|
||||
YAML;
|
||||
|
||||
Yaml::parse($yaml);
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```php
|
||||
|
||||
$yaml = <<<YAML
|
||||
"null": null key
|
||||
"true": boolean true
|
||||
"2.0": float key
|
||||
YAML;
|
||||
|
||||
Yaml::parse($yaml);
|
||||
```
|
||||
|
||||
* Omitted mapping values will be parsed as `null`.
|
||||
|
||||
* Omitting the key of a mapping is deprecated and will throw a `ParseException` in Symfony 4.0.
|
||||
|
||||
* Added support for dumping empty PHP arrays as YAML sequences:
|
||||
|
||||
```php
|
||||
Yaml::dump([], 0, 0, Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE);
|
||||
```
|
||||
|
||||
3.2.0
|
||||
-----
|
||||
|
||||
* Mappings with a colon (`:`) that is not followed by a whitespace are deprecated
|
||||
when the mapping key is not quoted and will lead to a `ParseException` in
|
||||
Symfony 4.0 (e.g. `foo:bar` must be `foo: bar`).
|
||||
|
||||
* Added support for parsing PHP constants:
|
||||
|
||||
```php
|
||||
Yaml::parse('!php/const:PHP_INT_MAX', Yaml::PARSE_CONSTANT);
|
||||
```
|
||||
|
||||
* Support for silently ignoring duplicate mapping keys in YAML has been
|
||||
deprecated and will lead to a `ParseException` in Symfony 4.0.
|
||||
|
||||
3.1.0
|
||||
-----
|
||||
|
||||
* Added support to dump `stdClass` and `ArrayAccess` objects as YAML mappings
|
||||
through the `Yaml::DUMP_OBJECT_AS_MAP` flag.
|
||||
|
||||
* Strings that are not UTF-8 encoded will be dumped as base64 encoded binary
|
||||
data.
|
||||
|
||||
* Added support for dumping multi line strings as literal blocks.
|
||||
|
||||
* Added support for parsing base64 encoded binary data when they are tagged
|
||||
with the `!!binary` tag.
|
||||
|
||||
* Added support for parsing timestamps as `\DateTime` objects:
|
||||
|
||||
```php
|
||||
Yaml::parse('2001-12-15 21:59:43.10 -5', Yaml::PARSE_DATETIME);
|
||||
```
|
||||
|
||||
* `\DateTime` and `\DateTimeImmutable` objects are dumped as YAML timestamps.
|
||||
|
||||
* Deprecated usage of `%` at the beginning of an unquoted string.
|
||||
|
||||
* Added support for customizing the YAML parser behavior through an optional bit field:
|
||||
|
||||
```php
|
||||
Yaml::parse('{ "foo": "bar", "fiz": "cat" }', Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE | Yaml::PARSE_OBJECT | Yaml::PARSE_OBJECT_FOR_MAP);
|
||||
```
|
||||
|
||||
* Added support for customizing the dumped YAML string through an optional bit field:
|
||||
|
||||
```php
|
||||
Yaml::dump(['foo' => new A(), 'bar' => 1], 0, 0, Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE | Yaml::DUMP_OBJECT);
|
||||
```
|
||||
|
||||
3.0.0
|
||||
-----
|
||||
|
||||
* Yaml::parse() now throws an exception when a blackslash is not escaped
|
||||
in double-quoted strings
|
||||
|
||||
2.8.0
|
||||
-----
|
||||
|
||||
* Deprecated usage of a colon in an unquoted mapping value
|
||||
* Deprecated usage of @, \`, | and > at the beginning of an unquoted string
|
||||
* When surrounding strings with double-quotes, you must now escape `\` characters. Not
|
||||
escaping those characters (when surrounded by double-quotes) is deprecated.
|
||||
|
||||
Before:
|
||||
|
||||
```yml
|
||||
class: "Foo\Var"
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```yml
|
||||
class: "Foo\\Var"
|
||||
```
|
||||
|
||||
2.1.0
|
||||
-----
|
||||
|
||||
* Yaml::parse() does not evaluate loaded files as PHP files by default
|
||||
anymore (call Yaml::enablePhpParsing() to get back the old behavior)
|
279
src/ncc/ThirdParty/Symfony/Yaml/Command/LintCommand.php
vendored
Normal file
279
src/ncc/ThirdParty/Symfony/Yaml/Command/LintCommand.php
vendored
Normal file
|
@ -0,0 +1,279 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace ncc\ThirdParty\Symfony\Yaml\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\CI\GithubActionReporter;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use ncc\ThirdParty\Symfony\Yaml\Exception\ParseException;
|
||||
use ncc\ThirdParty\Symfony\Yaml\Parser;
|
||||
use ncc\ThirdParty\Symfony\Yaml\Yaml;
|
||||
|
||||
/**
|
||||
* Validates YAML files syntax and outputs encountered errors.
|
||||
*
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
*/
|
||||
#[AsCommand(name: 'lint:yaml', description: 'Lint a YAML file and outputs encountered errors')]
|
||||
class LintCommand extends Command
|
||||
{
|
||||
private Parser $parser;
|
||||
private ?string $format = null;
|
||||
private bool $displayCorrectFiles;
|
||||
private ?\Closure $directoryIteratorProvider;
|
||||
private ?\Closure $isReadableProvider;
|
||||
|
||||
public function __construct(string $name = null, callable $directoryIteratorProvider = null, callable $isReadableProvider = null)
|
||||
{
|
||||
parent::__construct($name);
|
||||
|
||||
$this->directoryIteratorProvider = null === $directoryIteratorProvider ? null : $directoryIteratorProvider(...);
|
||||
$this->isReadableProvider = null === $isReadableProvider ? null : $isReadableProvider(...);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->addArgument('filename', InputArgument::IS_ARRAY, 'A file, a directory or "-" for reading from STDIN')
|
||||
->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format')
|
||||
->addOption('exclude', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Path(s) to exclude')
|
||||
->addOption('parse-tags', null, InputOption::VALUE_NEGATABLE, 'Parse custom tags', null)
|
||||
->setHelp(<<<EOF
|
||||
The <info>%command.name%</info> command lints a YAML file and outputs to STDOUT
|
||||
the first encountered syntax error.
|
||||
|
||||
You can validates YAML contents passed from STDIN:
|
||||
|
||||
<info>cat filename | php %command.full_name% -</info>
|
||||
|
||||
You can also validate the syntax of a file:
|
||||
|
||||
<info>php %command.full_name% filename</info>
|
||||
|
||||
Or of a whole directory:
|
||||
|
||||
<info>php %command.full_name% dirname</info>
|
||||
<info>php %command.full_name% dirname --format=json</info>
|
||||
|
||||
You can also exclude one or more specific files:
|
||||
|
||||
<info>php %command.full_name% dirname --exclude="dirname/foo.yaml" --exclude="dirname/bar.yaml"</info>
|
||||
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$filenames = (array) $input->getArgument('filename');
|
||||
$excludes = $input->getOption('exclude');
|
||||
$this->format = $input->getOption('format');
|
||||
$flags = $input->getOption('parse-tags');
|
||||
|
||||
if ('github' === $this->format && !class_exists(GithubActionReporter::class)) {
|
||||
throw new \InvalidArgumentException('The "github" format is only available since "symfony/console" >= 5.3.');
|
||||
}
|
||||
|
||||
if (null === $this->format) {
|
||||
// Autodetect format according to CI environment
|
||||
$this->format = class_exists(GithubActionReporter::class) && GithubActionReporter::isGithubActionEnvironment() ? 'github' : 'txt';
|
||||
}
|
||||
|
||||
$flags = $flags ? Yaml::PARSE_CUSTOM_TAGS : 0;
|
||||
|
||||
$this->displayCorrectFiles = $output->isVerbose();
|
||||
|
||||
if (['-'] === $filenames) {
|
||||
return $this->display($io, [$this->validate(file_get_contents('php://stdin'), $flags)]);
|
||||
}
|
||||
|
||||
if (!$filenames) {
|
||||
throw new RuntimeException('Please provide a filename or pipe file content to STDIN.');
|
||||
}
|
||||
|
||||
$filesInfo = [];
|
||||
foreach ($filenames as $filename) {
|
||||
if (!$this->isReadable($filename)) {
|
||||
throw new RuntimeException(sprintf('File or directory "%s" is not readable.', $filename));
|
||||
}
|
||||
|
||||
foreach ($this->getFiles($filename) as $file) {
|
||||
if (!\in_array($file->getPathname(), $excludes, true)) {
|
||||
$filesInfo[] = $this->validate(file_get_contents($file), $flags, $file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->display($io, $filesInfo);
|
||||
}
|
||||
|
||||
private function validate(string $content, int $flags, string $file = null)
|
||||
{
|
||||
$prevErrorHandler = set_error_handler(function ($level, $message, $file, $line) use (&$prevErrorHandler) {
|
||||
if (\E_USER_DEPRECATED === $level) {
|
||||
throw new ParseException($message, $this->getParser()->getRealCurrentLineNb() + 1);
|
||||
}
|
||||
|
||||
return $prevErrorHandler ? $prevErrorHandler($level, $message, $file, $line) : false;
|
||||
});
|
||||
|
||||
try {
|
||||
$this->getParser()->parse($content, Yaml::PARSE_CONSTANT | $flags);
|
||||
} catch (ParseException $e) {
|
||||
return ['file' => $file, 'line' => $e->getParsedLine(), 'valid' => false, 'message' => $e->getMessage()];
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
return ['file' => $file, 'valid' => true];
|
||||
}
|
||||
|
||||
private function display(SymfonyStyle $io, array $files): int
|
||||
{
|
||||
return match ($this->format) {
|
||||
'txt' => $this->displayTxt($io, $files),
|
||||
'json' => $this->displayJson($io, $files),
|
||||
'github' => $this->displayTxt($io, $files, true),
|
||||
default => throw new InvalidArgumentException(sprintf('The format "%s" is not supported.', $this->format)),
|
||||
};
|
||||
}
|
||||
|
||||
private function displayTxt(SymfonyStyle $io, array $filesInfo, bool $errorAsGithubAnnotations = false): int
|
||||
{
|
||||
$countFiles = \count($filesInfo);
|
||||
$erroredFiles = 0;
|
||||
$suggestTagOption = false;
|
||||
|
||||
if ($errorAsGithubAnnotations) {
|
||||
$githubReporter = new GithubActionReporter($io);
|
||||
}
|
||||
|
||||
foreach ($filesInfo as $info) {
|
||||
if ($info['valid'] && $this->displayCorrectFiles) {
|
||||
$io->comment('<info>OK</info>'.($info['file'] ? sprintf(' in %s', $info['file']) : ''));
|
||||
} elseif (!$info['valid']) {
|
||||
++$erroredFiles;
|
||||
$io->text('<error> ERROR </error>'.($info['file'] ? sprintf(' in %s', $info['file']) : ''));
|
||||
$io->text(sprintf('<error> >> %s</error>', $info['message']));
|
||||
|
||||
if (str_contains($info['message'], 'PARSE_CUSTOM_TAGS')) {
|
||||
$suggestTagOption = true;
|
||||
}
|
||||
|
||||
if ($errorAsGithubAnnotations) {
|
||||
$githubReporter->error($info['message'], $info['file'] ?? 'php://stdin', $info['line']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (0 === $erroredFiles) {
|
||||
$io->success(sprintf('All %d YAML files contain valid syntax.', $countFiles));
|
||||
} else {
|
||||
$io->warning(sprintf('%d YAML files have valid syntax and %d contain errors.%s', $countFiles - $erroredFiles, $erroredFiles, $suggestTagOption ? ' Use the --parse-tags option if you want parse custom tags.' : ''));
|
||||
}
|
||||
|
||||
return min($erroredFiles, 1);
|
||||
}
|
||||
|
||||
private function displayJson(SymfonyStyle $io, array $filesInfo): int
|
||||
{
|
||||
$errors = 0;
|
||||
|
||||
array_walk($filesInfo, function (&$v) use (&$errors) {
|
||||
$v['file'] = (string) $v['file'];
|
||||
if (!$v['valid']) {
|
||||
++$errors;
|
||||
}
|
||||
|
||||
if (isset($v['message']) && str_contains($v['message'], 'PARSE_CUSTOM_TAGS')) {
|
||||
$v['message'] .= ' Use the --parse-tags option if you want parse custom tags.';
|
||||
}
|
||||
});
|
||||
|
||||
$io->writeln(json_encode($filesInfo, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES));
|
||||
|
||||
return min($errors, 1);
|
||||
}
|
||||
|
||||
private function getFiles(string $fileOrDirectory): iterable
|
||||
{
|
||||
if (is_file($fileOrDirectory)) {
|
||||
yield new \SplFileInfo($fileOrDirectory);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->getDirectoryIterator($fileOrDirectory) as $file) {
|
||||
if (!\in_array($file->getExtension(), ['yml', 'yaml'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
yield $file;
|
||||
}
|
||||
}
|
||||
|
||||
private function getParser(): Parser
|
||||
{
|
||||
return $this->parser ??= new Parser();
|
||||
}
|
||||
|
||||
private function getDirectoryIterator(string $directory): iterable
|
||||
{
|
||||
$default = function ($directory) {
|
||||
return new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS),
|
||||
\RecursiveIteratorIterator::LEAVES_ONLY
|
||||
);
|
||||
};
|
||||
|
||||
if (null !== $this->directoryIteratorProvider) {
|
||||
return ($this->directoryIteratorProvider)($directory, $default);
|
||||
}
|
||||
|
||||
return $default($directory);
|
||||
}
|
||||
|
||||
private function isReadable(string $fileOrDirectory): bool
|
||||
{
|
||||
$default = function ($fileOrDirectory) {
|
||||
return is_readable($fileOrDirectory);
|
||||
};
|
||||
|
||||
if (null !== $this->isReadableProvider) {
|
||||
return ($this->isReadableProvider)($fileOrDirectory, $default);
|
||||
}
|
||||
|
||||
return $default($fileOrDirectory);
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestOptionValuesFor('format')) {
|
||||
$suggestions->suggestValues(['txt', 'json', 'github']);
|
||||
}
|
||||
}
|
||||
}
|
138
src/ncc/ThirdParty/Symfony/Yaml/Dumper.php
vendored
Normal file
138
src/ncc/ThirdParty/Symfony/Yaml/Dumper.php
vendored
Normal file
|
@ -0,0 +1,138 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace ncc\ThirdParty\Symfony\Yaml;
|
||||
|
||||
use ncc\ThirdParty\Symfony\Yaml\Tag\TaggedValue;
|
||||
|
||||
/**
|
||||
* Dumper dumps PHP variables to YAML strings.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class Dumper
|
||||
{
|
||||
/**
|
||||
* The amount of spaces to use for indentation of nested nodes.
|
||||
*/
|
||||
private int $indentation;
|
||||
|
||||
public function __construct(int $indentation = 4)
|
||||
{
|
||||
if ($indentation < 1) {
|
||||
throw new \InvalidArgumentException('The indentation must be greater than zero.');
|
||||
}
|
||||
|
||||
$this->indentation = $indentation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps a PHP value to YAML.
|
||||
*
|
||||
* @param mixed $input The PHP value
|
||||
* @param int $inline The level where you switch to inline YAML
|
||||
* @param int $indent The level of indentation (used internally)
|
||||
* @param int $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string
|
||||
*/
|
||||
public function dump(mixed $input, int $inline = 0, int $indent = 0, int $flags = 0): string
|
||||
{
|
||||
$output = '';
|
||||
$prefix = $indent ? str_repeat(' ', $indent) : '';
|
||||
$dumpObjectAsInlineMap = true;
|
||||
|
||||
if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($input instanceof \ArrayObject || $input instanceof \stdClass)) {
|
||||
$dumpObjectAsInlineMap = empty((array) $input);
|
||||
}
|
||||
|
||||
if ($inline <= 0 || (!\is_array($input) && !$input instanceof TaggedValue && $dumpObjectAsInlineMap) || empty($input)) {
|
||||
$output .= $prefix.Inline::dump($input, $flags);
|
||||
} else {
|
||||
$dumpAsMap = Inline::isHash($input);
|
||||
|
||||
foreach ($input as $key => $value) {
|
||||
if ('' !== $output && "\n" !== $output[-1]) {
|
||||
$output .= "\n";
|
||||
}
|
||||
|
||||
if (Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK & $flags && \is_string($value) && str_contains($value, "\n") && !str_contains($value, "\r")) {
|
||||
// If the first line starts with a space character, the spec requires a blockIndicationIndicator
|
||||
// http://www.yaml.org/spec/1.2/spec.html#id2793979
|
||||
$blockIndentationIndicator = str_starts_with($value, ' ') ? (string) $this->indentation : '';
|
||||
|
||||
if (isset($value[-2]) && "\n" === $value[-2] && "\n" === $value[-1]) {
|
||||
$blockChompingIndicator = '+';
|
||||
} elseif ("\n" === $value[-1]) {
|
||||
$blockChompingIndicator = '';
|
||||
} else {
|
||||
$blockChompingIndicator = '-';
|
||||
}
|
||||
|
||||
$output .= sprintf('%s%s%s |%s%s', $prefix, $dumpAsMap ? Inline::dump($key, $flags).':' : '-', '', $blockIndentationIndicator, $blockChompingIndicator);
|
||||
|
||||
foreach (explode("\n", $value) as $row) {
|
||||
if ('' === $row) {
|
||||
$output .= "\n";
|
||||
} else {
|
||||
$output .= sprintf("\n%s%s%s", $prefix, str_repeat(' ', $this->indentation), $row);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($value instanceof TaggedValue) {
|
||||
$output .= sprintf('%s%s !%s', $prefix, $dumpAsMap ? Inline::dump($key, $flags).':' : '-', $value->getTag());
|
||||
|
||||
if (Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK & $flags && \is_string($value->getValue()) && str_contains($value->getValue(), "\n") && !str_contains($value->getValue(), "\r\n")) {
|
||||
// If the first line starts with a space character, the spec requires a blockIndicationIndicator
|
||||
// http://www.yaml.org/spec/1.2/spec.html#id2793979
|
||||
$blockIndentationIndicator = str_starts_with($value->getValue(), ' ') ? (string) $this->indentation : '';
|
||||
$output .= sprintf(' |%s', $blockIndentationIndicator);
|
||||
|
||||
foreach (explode("\n", $value->getValue()) as $row) {
|
||||
$output .= sprintf("\n%s%s%s", $prefix, str_repeat(' ', $this->indentation), $row);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($inline - 1 <= 0 || null === $value->getValue() || \is_scalar($value->getValue())) {
|
||||
$output .= ' '.$this->dump($value->getValue(), $inline - 1, 0, $flags)."\n";
|
||||
} else {
|
||||
$output .= "\n";
|
||||
$output .= $this->dump($value->getValue(), $inline - 1, $dumpAsMap ? $indent + $this->indentation : $indent + 2, $flags);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$dumpObjectAsInlineMap = true;
|
||||
|
||||
if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($value instanceof \ArrayObject || $value instanceof \stdClass)) {
|
||||
$dumpObjectAsInlineMap = empty((array) $value);
|
||||
}
|
||||
|
||||
$willBeInlined = $inline - 1 <= 0 || !\is_array($value) && $dumpObjectAsInlineMap || empty($value);
|
||||
|
||||
$output .= sprintf('%s%s%s%s',
|
||||
$prefix,
|
||||
$dumpAsMap ? Inline::dump($key, $flags).':' : '-',
|
||||
$willBeInlined ? ' ' : "\n",
|
||||
$this->dump($value, $inline - 1, $willBeInlined ? 0 : $indent + $this->indentation, $flags)
|
||||
).($willBeInlined ? "\n" : '');
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
95
src/ncc/ThirdParty/Symfony/Yaml/Escaper.php
vendored
Normal file
95
src/ncc/ThirdParty/Symfony/Yaml/Escaper.php
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace ncc\ThirdParty\Symfony\Yaml;
|
||||
|
||||
/**
|
||||
* Escaper encapsulates escaping rules for single and double-quoted
|
||||
* YAML strings.
|
||||
*
|
||||
* @author Matthew Lewinski <matthew@lewinski.org>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class Escaper
|
||||
{
|
||||
// Characters that would cause a dumped string to require double quoting.
|
||||
public const REGEX_CHARACTER_TO_ESCAPE = "[\\x00-\\x1f]|\x7f|\xc2\x85|\xc2\xa0|\xe2\x80\xa8|\xe2\x80\xa9";
|
||||
|
||||
// Mapping arrays for escaping a double quoted string. The backslash is
|
||||
// first to ensure proper escaping because str_replace operates iteratively
|
||||
// on the input arrays. This ordering of the characters avoids the use of strtr,
|
||||
// which performs more slowly.
|
||||
private const ESCAPEES = ['\\', '\\\\', '\\"', '"',
|
||||
"\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07",
|
||||
"\x08", "\x09", "\x0a", "\x0b", "\x0c", "\x0d", "\x0e", "\x0f",
|
||||
"\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17",
|
||||
"\x18", "\x19", "\x1a", "\x1b", "\x1c", "\x1d", "\x1e", "\x1f",
|
||||
"\x7f",
|
||||
"\xc2\x85", "\xc2\xa0", "\xe2\x80\xa8", "\xe2\x80\xa9",
|
||||
];
|
||||
private const ESCAPED = ['\\\\', '\\"', '\\\\', '\\"',
|
||||
'\\0', '\\x01', '\\x02', '\\x03', '\\x04', '\\x05', '\\x06', '\\a',
|
||||
'\\b', '\\t', '\\n', '\\v', '\\f', '\\r', '\\x0e', '\\x0f',
|
||||
'\\x10', '\\x11', '\\x12', '\\x13', '\\x14', '\\x15', '\\x16', '\\x17',
|
||||
'\\x18', '\\x19', '\\x1a', '\\e', '\\x1c', '\\x1d', '\\x1e', '\\x1f',
|
||||
'\\x7f',
|
||||
'\\N', '\\_', '\\L', '\\P',
|
||||
];
|
||||
|
||||
/**
|
||||
* Determines if a PHP value would require double quoting in YAML.
|
||||
*
|
||||
* @param string $value A PHP value
|
||||
*/
|
||||
public static function requiresDoubleQuoting(string $value): bool
|
||||
{
|
||||
return 0 < preg_match('/'.self::REGEX_CHARACTER_TO_ESCAPE.'/u', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes and surrounds a PHP value with double quotes.
|
||||
*
|
||||
* @param string $value A PHP value
|
||||
*/
|
||||
public static function escapeWithDoubleQuotes(string $value): string
|
||||
{
|
||||
return sprintf('"%s"', str_replace(self::ESCAPEES, self::ESCAPED, $value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a PHP value would require single quoting in YAML.
|
||||
*
|
||||
* @param string $value A PHP value
|
||||
*/
|
||||
public static function requiresSingleQuoting(string $value): bool
|
||||
{
|
||||
// Determines if a PHP value is entirely composed of a value that would
|
||||
// require single quoting in YAML.
|
||||
if (\in_array(strtolower($value), ['null', '~', 'true', 'false', 'y', 'n', 'yes', 'no', 'on', 'off'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Determines if the PHP value contains any single characters that would
|
||||
// cause it to require single quoting in YAML.
|
||||
return 0 < preg_match('/[ \s \' " \: \{ \} \[ \] , & \* \# \?] | \A[ \- ? | < > = ! % @ ` \p{Zs}]/xu', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes and surrounds a PHP value with single quotes.
|
||||
*
|
||||
* @param string $value A PHP value
|
||||
*/
|
||||
public static function escapeWithSingleQuotes(string $value): string
|
||||
{
|
||||
return sprintf("'%s'", str_replace('\'', '\'\'', $value));
|
||||
}
|
||||
}
|
21
src/ncc/ThirdParty/Symfony/Yaml/Exception/DumpException.php
vendored
Normal file
21
src/ncc/ThirdParty/Symfony/Yaml/Exception/DumpException.php
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace ncc\ThirdParty\Symfony\Yaml\Exception;
|
||||
|
||||
/**
|
||||
* Exception class thrown when an error occurs during dumping.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class DumpException extends RuntimeException
|
||||
{
|
||||
}
|
21
src/ncc/ThirdParty/Symfony/Yaml/Exception/ExceptionInterface.php
vendored
Normal file
21
src/ncc/ThirdParty/Symfony/Yaml/Exception/ExceptionInterface.php
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace ncc\ThirdParty\Symfony\Yaml\Exception;
|
||||
|
||||
/**
|
||||
* Exception interface for all exceptions thrown by the component.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface ExceptionInterface extends \Throwable
|
||||
{
|
||||
}
|
126
src/ncc/ThirdParty/Symfony/Yaml/Exception/ParseException.php
vendored
Normal file
126
src/ncc/ThirdParty/Symfony/Yaml/Exception/ParseException.php
vendored
Normal file
|
@ -0,0 +1,126 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace ncc\ThirdParty\Symfony\Yaml\Exception;
|
||||
|
||||
/**
|
||||
* Exception class thrown when an error occurs during parsing.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class ParseException extends RuntimeException
|
||||
{
|
||||
private ?string $parsedFile;
|
||||
private int $parsedLine;
|
||||
private ?string $snippet;
|
||||
private string $rawMessage;
|
||||
|
||||
/**
|
||||
* @param string $message The error message
|
||||
* @param int $parsedLine The line where the error occurred
|
||||
* @param string|null $snippet The snippet of code near the problem
|
||||
* @param string|null $parsedFile The file name where the error occurred
|
||||
*/
|
||||
public function __construct(string $message, int $parsedLine = -1, string $snippet = null, string $parsedFile = null, \Throwable $previous = null)
|
||||
{
|
||||
$this->parsedFile = $parsedFile;
|
||||
$this->parsedLine = $parsedLine;
|
||||
$this->snippet = $snippet;
|
||||
$this->rawMessage = $message;
|
||||
|
||||
$this->updateRepr();
|
||||
|
||||
parent::__construct($this->message, 0, $previous);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the snippet of code near the error.
|
||||
*/
|
||||
public function getSnippet(): string
|
||||
{
|
||||
return $this->snippet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the snippet of code near the error.
|
||||
*/
|
||||
public function setSnippet(string $snippet)
|
||||
{
|
||||
$this->snippet = $snippet;
|
||||
|
||||
$this->updateRepr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the filename where the error occurred.
|
||||
*
|
||||
* This method returns null if a string is parsed.
|
||||
*/
|
||||
public function getParsedFile(): string
|
||||
{
|
||||
return $this->parsedFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the filename where the error occurred.
|
||||
*/
|
||||
public function setParsedFile(string $parsedFile)
|
||||
{
|
||||
$this->parsedFile = $parsedFile;
|
||||
|
||||
$this->updateRepr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the line where the error occurred.
|
||||
*/
|
||||
public function getParsedLine(): int
|
||||
{
|
||||
return $this->parsedLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the line where the error occurred.
|
||||
*/
|
||||
public function setParsedLine(int $parsedLine)
|
||||
{
|
||||
$this->parsedLine = $parsedLine;
|
||||
|
||||
$this->updateRepr();
|
||||
}
|
||||
|
||||
private function updateRepr()
|
||||
{
|
||||
$this->message = $this->rawMessage;
|
||||
|
||||
$dot = false;
|
||||
if (str_ends_with($this->message, '.')) {
|
||||
$this->message = substr($this->message, 0, -1);
|
||||
$dot = true;
|
||||
}
|
||||
|
||||
if (null !== $this->parsedFile) {
|
||||
$this->message .= sprintf(' in %s', json_encode($this->parsedFile, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
|
||||
if ($this->parsedLine >= 0) {
|
||||
$this->message .= sprintf(' at line %d', $this->parsedLine);
|
||||
}
|
||||
|
||||
if ($this->snippet) {
|
||||
$this->message .= sprintf(' (near "%s")', $this->snippet);
|
||||
}
|
||||
|
||||
if ($dot) {
|
||||
$this->message .= '.';
|
||||
}
|
||||
}
|
||||
}
|
21
src/ncc/ThirdParty/Symfony/Yaml/Exception/RuntimeException.php
vendored
Normal file
21
src/ncc/ThirdParty/Symfony/Yaml/Exception/RuntimeException.php
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace ncc\ThirdParty\Symfony\Yaml\Exception;
|
||||
|
||||
/**
|
||||
* Exception class thrown when an error occurs during parsing.
|
||||
*
|
||||
* @author Romain Neutron <imprec@gmail.com>
|
||||
*/
|
||||
class RuntimeException extends \RuntimeException implements ExceptionInterface
|
||||
{
|
||||
}
|
779
src/ncc/ThirdParty/Symfony/Yaml/Inline.php
vendored
Normal file
779
src/ncc/ThirdParty/Symfony/Yaml/Inline.php
vendored
Normal file
|
@ -0,0 +1,779 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace ncc\ThirdParty\Symfony\Yaml;
|
||||
|
||||
use ncc\ThirdParty\Symfony\Yaml\Exception\DumpException;
|
||||
use ncc\ThirdParty\Symfony\Yaml\Exception\ParseException;
|
||||
use ncc\ThirdParty\Symfony\Yaml\Tag\TaggedValue;
|
||||
|
||||
/**
|
||||
* Inline implements a YAML parser/dumper for the YAML inline syntax.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class Inline
|
||||
{
|
||||
public const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*+(?:\\\\.[^"\\\\]*+)*+)"|\'([^\']*+(?:\'\'[^\']*+)*+)\')';
|
||||
|
||||
public static int $parsedLineNumber = -1;
|
||||
public static ?string $parsedFilename = null;
|
||||
|
||||
private static bool $exceptionOnInvalidType = false;
|
||||
private static bool $objectSupport = false;
|
||||
private static bool $objectForMap = false;
|
||||
private static bool $constantSupport = false;
|
||||
|
||||
public static function initialize(int $flags, int $parsedLineNumber = null, string $parsedFilename = null)
|
||||
{
|
||||
self::$exceptionOnInvalidType = (bool) (Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE & $flags);
|
||||
self::$objectSupport = (bool) (Yaml::PARSE_OBJECT & $flags);
|
||||
self::$objectForMap = (bool) (Yaml::PARSE_OBJECT_FOR_MAP & $flags);
|
||||
self::$constantSupport = (bool) (Yaml::PARSE_CONSTANT & $flags);
|
||||
self::$parsedFilename = $parsedFilename;
|
||||
|
||||
if (null !== $parsedLineNumber) {
|
||||
self::$parsedLineNumber = $parsedLineNumber;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a YAML string to a PHP value.
|
||||
*
|
||||
* @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior
|
||||
* @param array $references Mapping of variable names to values
|
||||
*
|
||||
* @throws ParseException
|
||||
*/
|
||||
public static function parse(string $value = null, int $flags = 0, array &$references = []): mixed
|
||||
{
|
||||
self::initialize($flags);
|
||||
|
||||
$value = trim($value);
|
||||
|
||||
if ('' === $value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
$tag = self::parseTag($value, $i, $flags);
|
||||
switch ($value[$i]) {
|
||||
case '[':
|
||||
$result = self::parseSequence($value, $flags, $i, $references);
|
||||
++$i;
|
||||
break;
|
||||
case '{':
|
||||
$result = self::parseMapping($value, $flags, $i, $references);
|
||||
++$i;
|
||||
break;
|
||||
default:
|
||||
$result = self::parseScalar($value, $flags, null, $i, null === $tag, $references);
|
||||
}
|
||||
|
||||
// some comments are allowed at the end
|
||||
if (preg_replace('/\s*#.*$/A', '', substr($value, $i))) {
|
||||
throw new ParseException(sprintf('Unexpected characters near "%s".', substr($value, $i)), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
|
||||
}
|
||||
|
||||
if (null !== $tag && '' !== $tag) {
|
||||
return new TaggedValue($tag, $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps a given PHP variable to a YAML string.
|
||||
*
|
||||
* @param mixed $value The PHP variable to convert
|
||||
* @param int $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string
|
||||
*
|
||||
* @throws DumpException When trying to dump PHP resource
|
||||
*/
|
||||
public static function dump(mixed $value, int $flags = 0): string
|
||||
{
|
||||
switch (true) {
|
||||
case \is_resource($value):
|
||||
if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) {
|
||||
throw new DumpException(sprintf('Unable to dump PHP resources in a YAML file ("%s").', get_resource_type($value)));
|
||||
}
|
||||
|
||||
return self::dumpNull($flags);
|
||||
case $value instanceof \DateTimeInterface:
|
||||
return $value->format('c');
|
||||
case $value instanceof \UnitEnum:
|
||||
return sprintf('!php/const %s::%s', \get_class($value), $value->name);
|
||||
case \is_object($value):
|
||||
if ($value instanceof TaggedValue) {
|
||||
return '!'.$value->getTag().' '.self::dump($value->getValue(), $flags);
|
||||
}
|
||||
|
||||
if (Yaml::DUMP_OBJECT & $flags) {
|
||||
return '!php/object '.self::dump(serialize($value));
|
||||
}
|
||||
|
||||
if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($value instanceof \stdClass || $value instanceof \ArrayObject)) {
|
||||
$output = [];
|
||||
|
||||
foreach ($value as $key => $val) {
|
||||
$output[] = sprintf('%s: %s', self::dump($key, $flags), self::dump($val, $flags));
|
||||
}
|
||||
|
||||
return sprintf('{ %s }', implode(', ', $output));
|
||||
}
|
||||
|
||||
if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) {
|
||||
throw new DumpException('Object support when dumping a YAML file has been disabled.');
|
||||
}
|
||||
|
||||
return self::dumpNull($flags);
|
||||
case \is_array($value):
|
||||
return self::dumpArray($value, $flags);
|
||||
case null === $value:
|
||||
return self::dumpNull($flags);
|
||||
case true === $value:
|
||||
return 'true';
|
||||
case false === $value:
|
||||
return 'false';
|
||||
case \is_int($value):
|
||||
return $value;
|
||||
case is_numeric($value) && false === strpbrk($value, "\f\n\r\t\v"):
|
||||
$locale = setlocale(\LC_NUMERIC, 0);
|
||||
if (false !== $locale) {
|
||||
setlocale(\LC_NUMERIC, 'C');
|
||||
}
|
||||
if (\is_float($value)) {
|
||||
$repr = (string) $value;
|
||||
if (is_infinite($value)) {
|
||||
$repr = str_ireplace('INF', '.Inf', $repr);
|
||||
} elseif (floor($value) == $value && $repr == $value) {
|
||||
// Preserve float data type since storing a whole number will result in integer value.
|
||||
if (!str_contains($repr, 'E')) {
|
||||
$repr = $repr.'.0';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$repr = \is_string($value) ? "'$value'" : (string) $value;
|
||||
}
|
||||
if (false !== $locale) {
|
||||
setlocale(\LC_NUMERIC, $locale);
|
||||
}
|
||||
|
||||
return $repr;
|
||||
case '' == $value:
|
||||
return "''";
|
||||
case self::isBinaryString($value):
|
||||
return '!!binary '.base64_encode($value);
|
||||
case Escaper::requiresDoubleQuoting($value):
|
||||
return Escaper::escapeWithDoubleQuotes($value);
|
||||
case Escaper::requiresSingleQuoting($value):
|
||||
$singleQuoted = Escaper::escapeWithSingleQuotes($value);
|
||||
if (!str_contains($value, "'")) {
|
||||
return $singleQuoted;
|
||||
}
|
||||
// Attempt double-quoting the string instead to see if it's more efficient.
|
||||
$doubleQuoted = Escaper::escapeWithDoubleQuotes($value);
|
||||
|
||||
return \strlen($doubleQuoted) < \strlen($singleQuoted) ? $doubleQuoted : $singleQuoted;
|
||||
case Parser::preg_match('{^[0-9]+[_0-9]*$}', $value):
|
||||
case Parser::preg_match(self::getHexRegex(), $value):
|
||||
case Parser::preg_match(self::getTimestampRegex(), $value):
|
||||
return Escaper::escapeWithSingleQuotes($value);
|
||||
default:
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given array is hash or just normal indexed array.
|
||||
*/
|
||||
public static function isHash(array|\ArrayObject|\stdClass $value): bool
|
||||
{
|
||||
if ($value instanceof \stdClass || $value instanceof \ArrayObject) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$expectedKey = 0;
|
||||
|
||||
foreach ($value as $key => $val) {
|
||||
if ($key !== $expectedKey++) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps a PHP array to a YAML string.
|
||||
*
|
||||
* @param array $value The PHP array to dump
|
||||
* @param int $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string
|
||||
*/
|
||||
private static function dumpArray(array $value, int $flags): string
|
||||
{
|
||||
// array
|
||||
if (($value || Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE & $flags) && !self::isHash($value)) {
|
||||
$output = [];
|
||||
foreach ($value as $val) {
|
||||
$output[] = self::dump($val, $flags);
|
||||
}
|
||||
|
||||
return sprintf('[%s]', implode(', ', $output));
|
||||
}
|
||||
|
||||
// hash
|
||||
$output = [];
|
||||
foreach ($value as $key => $val) {
|
||||
$output[] = sprintf('%s: %s', self::dump($key, $flags), self::dump($val, $flags));
|
||||
}
|
||||
|
||||
return sprintf('{ %s }', implode(', ', $output));
|
||||
}
|
||||
|
||||
private static function dumpNull(int $flags): string
|
||||
{
|
||||
if (Yaml::DUMP_NULL_AS_TILDE & $flags) {
|
||||
return '~';
|
||||
}
|
||||
|
||||
return 'null';
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a YAML scalar.
|
||||
*
|
||||
* @throws ParseException When malformed inline YAML string is parsed
|
||||
*/
|
||||
public static function parseScalar(string $scalar, int $flags = 0, array $delimiters = null, int &$i = 0, bool $evaluate = true, array &$references = [], bool &$isQuoted = null): mixed
|
||||
{
|
||||
if (\in_array($scalar[$i], ['"', "'"], true)) {
|
||||
// quoted scalar
|
||||
$isQuoted = true;
|
||||
$output = self::parseQuotedScalar($scalar, $i);
|
||||
|
||||
if (null !== $delimiters) {
|
||||
$tmp = ltrim(substr($scalar, $i), " \n");
|
||||
if ('' === $tmp) {
|
||||
throw new ParseException(sprintf('Unexpected end of line, expected one of "%s".', implode('', $delimiters)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
|
||||
}
|
||||
if (!\in_array($tmp[0], $delimiters)) {
|
||||
throw new ParseException(sprintf('Unexpected characters (%s).', substr($scalar, $i)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// "normal" string
|
||||
$isQuoted = false;
|
||||
|
||||
if (!$delimiters) {
|
||||
$output = substr($scalar, $i);
|
||||
$i += \strlen($output);
|
||||
|
||||
// remove comments
|
||||
if (Parser::preg_match('/[ \t]+#/', $output, $match, \PREG_OFFSET_CAPTURE)) {
|
||||
$output = substr($output, 0, $match[0][1]);
|
||||
}
|
||||
} elseif (Parser::preg_match('/^(.*?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) {
|
||||
$output = $match[1];
|
||||
$i += \strlen($output);
|
||||
$output = trim($output);
|
||||
} else {
|
||||
throw new ParseException(sprintf('Malformed inline YAML string: "%s".', $scalar), self::$parsedLineNumber + 1, null, self::$parsedFilename);
|
||||
}
|
||||
|
||||
// a non-quoted string cannot start with @ or ` (reserved) nor with a scalar indicator (| or >)
|
||||
if ($output && ('@' === $output[0] || '`' === $output[0] || '|' === $output[0] || '>' === $output[0] || '%' === $output[0])) {
|
||||
throw new ParseException(sprintf('The reserved indicator "%s" cannot start a plain scalar; you need to quote the scalar.', $output[0]), self::$parsedLineNumber + 1, $output, self::$parsedFilename);
|
||||
}
|
||||
|
||||
if ($evaluate) {
|
||||
$output = self::evaluateScalar($output, $flags, $references, $isQuoted);
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a YAML quoted scalar.
|
||||
*
|
||||
* @throws ParseException When malformed inline YAML string is parsed
|
||||
*/
|
||||
private static function parseQuotedScalar(string $scalar, int &$i = 0): string
|
||||
{
|
||||
if (!Parser::preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) {
|
||||
throw new ParseException(sprintf('Malformed inline YAML string: "%s".', substr($scalar, $i)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
|
||||
}
|
||||
|
||||
$output = substr($match[0], 1, -1);
|
||||
|
||||
$unescaper = new Unescaper();
|
||||
if ('"' == $scalar[$i]) {
|
||||
$output = $unescaper->unescapeDoubleQuotedString($output);
|
||||
} else {
|
||||
$output = $unescaper->unescapeSingleQuotedString($output);
|
||||
}
|
||||
|
||||
$i += \strlen($match[0]);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a YAML sequence.
|
||||
*
|
||||
* @throws ParseException When malformed inline YAML string is parsed
|
||||
*/
|
||||
private static function parseSequence(string $sequence, int $flags, int &$i = 0, array &$references = []): array
|
||||
{
|
||||
$output = [];
|
||||
$len = \strlen($sequence);
|
||||
++$i;
|
||||
|
||||
// [foo, bar, ...]
|
||||
while ($i < $len) {
|
||||
if (']' === $sequence[$i]) {
|
||||
return $output;
|
||||
}
|
||||
if (',' === $sequence[$i] || ' ' === $sequence[$i]) {
|
||||
++$i;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$tag = self::parseTag($sequence, $i, $flags);
|
||||
switch ($sequence[$i]) {
|
||||
case '[':
|
||||
// nested sequence
|
||||
$value = self::parseSequence($sequence, $flags, $i, $references);
|
||||
break;
|
||||
case '{':
|
||||
// nested mapping
|
||||
$value = self::parseMapping($sequence, $flags, $i, $references);
|
||||
break;
|
||||
default:
|
||||
$value = self::parseScalar($sequence, $flags, [',', ']'], $i, null === $tag, $references, $isQuoted);
|
||||
|
||||
// the value can be an array if a reference has been resolved to an array var
|
||||
if (\is_string($value) && !$isQuoted && str_contains($value, ': ')) {
|
||||
// embedded mapping?
|
||||
try {
|
||||
$pos = 0;
|
||||
$value = self::parseMapping('{'.$value.'}', $flags, $pos, $references);
|
||||
} catch (\InvalidArgumentException) {
|
||||
// no, it's not
|
||||
}
|
||||
}
|
||||
|
||||
if (!$isQuoted && \is_string($value) && '' !== $value && '&' === $value[0] && Parser::preg_match(Parser::REFERENCE_PATTERN, $value, $matches)) {
|
||||
$references[$matches['ref']] = $matches['value'];
|
||||
$value = $matches['value'];
|
||||
}
|
||||
|
||||
--$i;
|
||||
}
|
||||
|
||||
if (null !== $tag && '' !== $tag) {
|
||||
$value = new TaggedValue($tag, $value);
|
||||
}
|
||||
|
||||
$output[] = $value;
|
||||
|
||||
++$i;
|
||||
}
|
||||
|
||||
throw new ParseException(sprintf('Malformed inline YAML string: "%s".', $sequence), self::$parsedLineNumber + 1, null, self::$parsedFilename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a YAML mapping.
|
||||
*
|
||||
* @throws ParseException When malformed inline YAML string is parsed
|
||||
*/
|
||||
private static function parseMapping(string $mapping, int $flags, int &$i = 0, array &$references = []): array|\stdClass
|
||||
{
|
||||
$output = [];
|
||||
$len = \strlen($mapping);
|
||||
++$i;
|
||||
$allowOverwrite = false;
|
||||
|
||||
// {foo: bar, bar:foo, ...}
|
||||
while ($i < $len) {
|
||||
switch ($mapping[$i]) {
|
||||
case ' ':
|
||||
case ',':
|
||||
case "\n":
|
||||
++$i;
|
||||
continue 2;
|
||||
case '}':
|
||||
if (self::$objectForMap) {
|
||||
return (object) $output;
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
// key
|
||||
$offsetBeforeKeyParsing = $i;
|
||||
$isKeyQuoted = \in_array($mapping[$i], ['"', "'"], true);
|
||||
$key = self::parseScalar($mapping, $flags, [':', ' '], $i, false);
|
||||
|
||||
if ($offsetBeforeKeyParsing === $i) {
|
||||
throw new ParseException('Missing mapping key.', self::$parsedLineNumber + 1, $mapping);
|
||||
}
|
||||
|
||||
if ('!php/const' === $key) {
|
||||
$key .= ' '.self::parseScalar($mapping, $flags, [':'], $i, false);
|
||||
$key = self::evaluateScalar($key, $flags);
|
||||
}
|
||||
|
||||
if (false === $i = strpos($mapping, ':', $i)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$isKeyQuoted) {
|
||||
$evaluatedKey = self::evaluateScalar($key, $flags, $references);
|
||||
|
||||
if ('' !== $key && $evaluatedKey !== $key && !\is_string($evaluatedKey) && !\is_int($evaluatedKey)) {
|
||||
throw new ParseException('Implicit casting of incompatible mapping keys to strings is not supported. Quote your evaluable mapping keys instead.', self::$parsedLineNumber + 1, $mapping);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$isKeyQuoted && (!isset($mapping[$i + 1]) || !\in_array($mapping[$i + 1], [' ', ',', '[', ']', '{', '}', "\n"], true))) {
|
||||
throw new ParseException('Colons must be followed by a space or an indication character (i.e. " ", ",", "[", "]", "{", "}").', self::$parsedLineNumber + 1, $mapping);
|
||||
}
|
||||
|
||||
if ('<<' === $key) {
|
||||
$allowOverwrite = true;
|
||||
}
|
||||
|
||||
while ($i < $len) {
|
||||
if (':' === $mapping[$i] || ' ' === $mapping[$i] || "\n" === $mapping[$i]) {
|
||||
++$i;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$tag = self::parseTag($mapping, $i, $flags);
|
||||
switch ($mapping[$i]) {
|
||||
case '[':
|
||||
// nested sequence
|
||||
$value = self::parseSequence($mapping, $flags, $i, $references);
|
||||
// Spec: Keys MUST be unique; first one wins.
|
||||
// Parser cannot abort this mapping earlier, since lines
|
||||
// are processed sequentially.
|
||||
// But overwriting is allowed when a merge node is used in current block.
|
||||
if ('<<' === $key) {
|
||||
foreach ($value as $parsedValue) {
|
||||
$output += $parsedValue;
|
||||
}
|
||||
} elseif ($allowOverwrite || !isset($output[$key])) {
|
||||
if (null !== $tag) {
|
||||
$output[$key] = new TaggedValue($tag, $value);
|
||||
} else {
|
||||
$output[$key] = $value;
|
||||
}
|
||||
} elseif (isset($output[$key])) {
|
||||
throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), self::$parsedLineNumber + 1, $mapping);
|
||||
}
|
||||
break;
|
||||
case '{':
|
||||
// nested mapping
|
||||
$value = self::parseMapping($mapping, $flags, $i, $references);
|
||||
// Spec: Keys MUST be unique; first one wins.
|
||||
// Parser cannot abort this mapping earlier, since lines
|
||||
// are processed sequentially.
|
||||
// But overwriting is allowed when a merge node is used in current block.
|
||||
if ('<<' === $key) {
|
||||
$output += $value;
|
||||
} elseif ($allowOverwrite || !isset($output[$key])) {
|
||||
if (null !== $tag) {
|
||||
$output[$key] = new TaggedValue($tag, $value);
|
||||
} else {
|
||||
$output[$key] = $value;
|
||||
}
|
||||
} elseif (isset($output[$key])) {
|
||||
throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), self::$parsedLineNumber + 1, $mapping);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$value = self::parseScalar($mapping, $flags, [',', '}', "\n"], $i, null === $tag, $references, $isValueQuoted);
|
||||
// Spec: Keys MUST be unique; first one wins.
|
||||
// Parser cannot abort this mapping earlier, since lines
|
||||
// are processed sequentially.
|
||||
// But overwriting is allowed when a merge node is used in current block.
|
||||
if ('<<' === $key) {
|
||||
$output += $value;
|
||||
} elseif ($allowOverwrite || !isset($output[$key])) {
|
||||
if (!$isValueQuoted && \is_string($value) && '' !== $value && '&' === $value[0] && Parser::preg_match(Parser::REFERENCE_PATTERN, $value, $matches)) {
|
||||
$references[$matches['ref']] = $matches['value'];
|
||||
$value = $matches['value'];
|
||||
}
|
||||
|
||||
if (null !== $tag) {
|
||||
$output[$key] = new TaggedValue($tag, $value);
|
||||
} else {
|
||||
$output[$key] = $value;
|
||||
}
|
||||
} elseif (isset($output[$key])) {
|
||||
throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), self::$parsedLineNumber + 1, $mapping);
|
||||
}
|
||||
--$i;
|
||||
}
|
||||
++$i;
|
||||
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ParseException(sprintf('Malformed inline YAML string: "%s".', $mapping), self::$parsedLineNumber + 1, null, self::$parsedFilename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates scalars and replaces magic values.
|
||||
*
|
||||
* @throws ParseException when object parsing support was disabled and the parser detected a PHP object or when a reference could not be resolved
|
||||
*/
|
||||
private static function evaluateScalar(string $scalar, int $flags, array &$references = [], bool &$isQuotedString = null): mixed
|
||||
{
|
||||
$isQuotedString = false;
|
||||
$scalar = trim($scalar);
|
||||
|
||||
if (str_starts_with($scalar, '*')) {
|
||||
if (false !== $pos = strpos($scalar, '#')) {
|
||||
$value = substr($scalar, 1, $pos - 2);
|
||||
} else {
|
||||
$value = substr($scalar, 1);
|
||||
}
|
||||
|
||||
// an unquoted *
|
||||
if (false === $value || '' === $value) {
|
||||
throw new ParseException('A reference must contain at least one character.', self::$parsedLineNumber + 1, $value, self::$parsedFilename);
|
||||
}
|
||||
|
||||
if (!\array_key_exists($value, $references)) {
|
||||
throw new ParseException(sprintf('Reference "%s" does not exist.', $value), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
|
||||
}
|
||||
|
||||
return $references[$value];
|
||||
}
|
||||
|
||||
$scalarLower = strtolower($scalar);
|
||||
|
||||
switch (true) {
|
||||
case 'null' === $scalarLower:
|
||||
case '' === $scalar:
|
||||
case '~' === $scalar:
|
||||
return null;
|
||||
case 'true' === $scalarLower:
|
||||
return true;
|
||||
case 'false' === $scalarLower:
|
||||
return false;
|
||||
case '!' === $scalar[0]:
|
||||
switch (true) {
|
||||
case str_starts_with($scalar, '!!str '):
|
||||
$s = (string) substr($scalar, 6);
|
||||
|
||||
if (\in_array($s[0] ?? '', ['"', "'"], true)) {
|
||||
$isQuotedString = true;
|
||||
$s = self::parseQuotedScalar($s);
|
||||
}
|
||||
|
||||
return $s;
|
||||
case str_starts_with($scalar, '! '):
|
||||
return substr($scalar, 2);
|
||||
case str_starts_with($scalar, '!php/object'):
|
||||
if (self::$objectSupport) {
|
||||
if (!isset($scalar[12])) {
|
||||
throw new ParseException('Missing value for tag "!php/object".', self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
|
||||
}
|
||||
|
||||
return unserialize(self::parseScalar(substr($scalar, 12)));
|
||||
}
|
||||
|
||||
if (self::$exceptionOnInvalidType) {
|
||||
throw new ParseException('Object support when parsing a YAML file has been disabled.', self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
|
||||
}
|
||||
|
||||
return null;
|
||||
case str_starts_with($scalar, '!php/const'):
|
||||
if (self::$constantSupport) {
|
||||
if (!isset($scalar[11])) {
|
||||
throw new ParseException('Missing value for tag "!php/const".', self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
if (\defined($const = self::parseScalar(substr($scalar, 11), 0, null, $i, false))) {
|
||||
return \constant($const);
|
||||
}
|
||||
|
||||
throw new ParseException(sprintf('The constant "%s" is not defined.', $const), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
|
||||
}
|
||||
if (self::$exceptionOnInvalidType) {
|
||||
throw new ParseException(sprintf('The string "%s" could not be parsed as a constant. Did you forget to pass the "Yaml::PARSE_CONSTANT" flag to the parser?', $scalar), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
|
||||
}
|
||||
|
||||
return null;
|
||||
case str_starts_with($scalar, '!!float '):
|
||||
return (float) substr($scalar, 8);
|
||||
case str_starts_with($scalar, '!!binary '):
|
||||
return self::evaluateBinaryScalar(substr($scalar, 9));
|
||||
}
|
||||
|
||||
throw new ParseException(sprintf('The string "%s" could not be parsed as it uses an unsupported built-in tag.', $scalar), self::$parsedLineNumber, $scalar, self::$parsedFilename);
|
||||
case preg_match('/^(?:\+|-)?0o(?P<value>[0-7_]++)$/', $scalar, $matches):
|
||||
$value = str_replace('_', '', $matches['value']);
|
||||
|
||||
if ('-' === $scalar[0]) {
|
||||
return -octdec($value);
|
||||
}
|
||||
|
||||
return octdec($value);
|
||||
// Optimize for returning strings.
|
||||
case \in_array($scalar[0], ['+', '-', '.'], true) || is_numeric($scalar[0]):
|
||||
if (Parser::preg_match('{^[+-]?[0-9][0-9_]*$}', $scalar)) {
|
||||
$scalar = str_replace('_', '', $scalar);
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
case ctype_digit($scalar):
|
||||
case '-' === $scalar[0] && ctype_digit(substr($scalar, 1)):
|
||||
$cast = (int) $scalar;
|
||||
|
||||
return ($scalar === (string) $cast) ? $cast : $scalar;
|
||||
case is_numeric($scalar):
|
||||
case Parser::preg_match(self::getHexRegex(), $scalar):
|
||||
$scalar = str_replace('_', '', $scalar);
|
||||
|
||||
return '0x' === $scalar[0].$scalar[1] ? hexdec($scalar) : (float) $scalar;
|
||||
case '.inf' === $scalarLower:
|
||||
case '.nan' === $scalarLower:
|
||||
return -log(0);
|
||||
case '-.inf' === $scalarLower:
|
||||
return log(0);
|
||||
case Parser::preg_match('/^(-|\+)?[0-9][0-9_]*(\.[0-9_]+)?$/', $scalar):
|
||||
return (float) str_replace('_', '', $scalar);
|
||||
case Parser::preg_match(self::getTimestampRegex(), $scalar):
|
||||
// When no timezone is provided in the parsed date, YAML spec says we must assume UTC.
|
||||
$time = new \DateTime($scalar, new \DateTimeZone('UTC'));
|
||||
|
||||
if (Yaml::PARSE_DATETIME & $flags) {
|
||||
return $time;
|
||||
}
|
||||
|
||||
try {
|
||||
if (false !== $scalar = $time->getTimestamp()) {
|
||||
return $scalar;
|
||||
}
|
||||
} catch (\ValueError) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
return $time->format('U');
|
||||
}
|
||||
}
|
||||
|
||||
return (string) $scalar;
|
||||
}
|
||||
|
||||
private static function parseTag(string $value, int &$i, int $flags): ?string
|
||||
{
|
||||
if ('!' !== $value[$i]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$tagLength = strcspn($value, " \t\n[]{},", $i + 1);
|
||||
$tag = substr($value, $i + 1, $tagLength);
|
||||
|
||||
$nextOffset = $i + $tagLength + 1;
|
||||
$nextOffset += strspn($value, ' ', $nextOffset);
|
||||
|
||||
if ('' === $tag && (!isset($value[$nextOffset]) || \in_array($value[$nextOffset], [']', '}', ','], true))) {
|
||||
throw new ParseException('Using the unquoted scalar value "!" is not supported. You must quote it.', self::$parsedLineNumber + 1, $value, self::$parsedFilename);
|
||||
}
|
||||
|
||||
// Is followed by a scalar and is a built-in tag
|
||||
if ('' !== $tag && (!isset($value[$nextOffset]) || !\in_array($value[$nextOffset], ['[', '{'], true)) && ('!' === $tag[0] || 'str' === $tag || 'php/const' === $tag || 'php/object' === $tag)) {
|
||||
// Manage in {@link self::evaluateScalar()}
|
||||
return null;
|
||||
}
|
||||
|
||||
$i = $nextOffset;
|
||||
|
||||
// Built-in tags
|
||||
if ('' !== $tag && '!' === $tag[0]) {
|
||||
throw new ParseException(sprintf('The built-in tag "!%s" is not implemented.', $tag), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
|
||||
}
|
||||
|
||||
if ('' !== $tag && !isset($value[$i])) {
|
||||
throw new ParseException(sprintf('Missing value for tag "%s".', $tag), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
|
||||
}
|
||||
|
||||
if ('' === $tag || Yaml::PARSE_CUSTOM_TAGS & $flags) {
|
||||
return $tag;
|
||||
}
|
||||
|
||||
throw new ParseException(sprintf('Tags support is not enabled. Enable the "Yaml::PARSE_CUSTOM_TAGS" flag to use "!%s".', $tag), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
|
||||
}
|
||||
|
||||
public static function evaluateBinaryScalar(string $scalar): string
|
||||
{
|
||||
$parsedBinaryData = self::parseScalar(preg_replace('/\s/', '', $scalar));
|
||||
|
||||
if (0 !== (\strlen($parsedBinaryData) % 4)) {
|
||||
throw new ParseException(sprintf('The normalized base64 encoded data (data without whitespace characters) length must be a multiple of four (%d bytes given).', \strlen($parsedBinaryData)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
|
||||
}
|
||||
|
||||
if (!Parser::preg_match('#^[A-Z0-9+/]+={0,2}$#i', $parsedBinaryData)) {
|
||||
throw new ParseException(sprintf('The base64 encoded data (%s) contains invalid characters.', $parsedBinaryData), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
|
||||
}
|
||||
|
||||
return base64_decode($parsedBinaryData, true);
|
||||
}
|
||||
|
||||
private static function isBinaryString(string $value): bool
|
||||
{
|
||||
return !preg_match('//u', $value) || preg_match('/[^\x00\x07-\x0d\x1B\x20-\xff]/', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a regex that matches a YAML date.
|
||||
*
|
||||
* @see http://www.yaml.org/spec/1.2/spec.html#id2761573
|
||||
*/
|
||||
private static function getTimestampRegex(): string
|
||||
{
|
||||
return <<<EOF
|
||||
~^
|
||||
(?P<year>[0-9][0-9][0-9][0-9])
|
||||
-(?P<month>[0-9][0-9]?)
|
||||
-(?P<day>[0-9][0-9]?)
|
||||
(?:(?:[Tt]|[ \t]+)
|
||||
(?P<hour>[0-9][0-9]?)
|
||||
:(?P<minute>[0-9][0-9])
|
||||
:(?P<second>[0-9][0-9])
|
||||
(?:\.(?P<fraction>[0-9]*))?
|
||||
(?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
|
||||
(?::(?P<tz_minute>[0-9][0-9]))?))?)?
|
||||
$~x
|
||||
EOF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a regex that matches a YAML number in hexadecimal notation.
|
||||
*/
|
||||
private static function getHexRegex(): string
|
||||
{
|
||||
return '~^0x[0-9a-f_]++$~i';
|
||||
}
|
||||
}
|
|
@ -1,16 +1,14 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Austin Hyde
|
||||
Copyright (c) 2004-2022 Fabien Potencier
|
||||
|
||||
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:
|
||||
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 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,
|
||||
|
@ -18,4 +16,4 @@ 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.
|
||||
THE SOFTWARE.
|
1255
src/ncc/ThirdParty/Symfony/Yaml/Parser.php
vendored
Normal file
1255
src/ncc/ThirdParty/Symfony/Yaml/Parser.php
vendored
Normal file
File diff suppressed because it is too large
Load diff
13
src/ncc/ThirdParty/Symfony/Yaml/README.md
vendored
Normal file
13
src/ncc/ThirdParty/Symfony/Yaml/README.md
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
Yaml Component
|
||||
==============
|
||||
|
||||
The Yaml component loads and dumps YAML files.
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
* [Documentation](https://symfony.com/doc/current/components/yaml.html)
|
||||
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
|
||||
* [Report issues](https://github.com/symfony/symfony/issues) and
|
||||
[send Pull Requests](https://github.com/symfony/symfony/pulls)
|
||||
in the [main Symfony repository](https://github.com/symfony/symfony)
|
38
src/ncc/ThirdParty/Symfony/Yaml/Tag/TaggedValue.php
vendored
Normal file
38
src/ncc/ThirdParty/Symfony/Yaml/Tag/TaggedValue.php
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace ncc\ThirdParty\Symfony\Yaml\Tag;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
* @author Guilhem N. <egetick@gmail.com>
|
||||
*/
|
||||
final class TaggedValue
|
||||
{
|
||||
private string $tag;
|
||||
private mixed $value;
|
||||
|
||||
public function __construct(string $tag, mixed $value)
|
||||
{
|
||||
$this->tag = $tag;
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function getTag(): string
|
||||
{
|
||||
return $this->tag;
|
||||
}
|
||||
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
110
src/ncc/ThirdParty/Symfony/Yaml/Unescaper.php
vendored
Normal file
110
src/ncc/ThirdParty/Symfony/Yaml/Unescaper.php
vendored
Normal file
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace ncc\ThirdParty\Symfony\Yaml;
|
||||
|
||||
use ncc\ThirdParty\Symfony\Yaml\Exception\ParseException;
|
||||
|
||||
/**
|
||||
* Unescaper encapsulates unescaping rules for single and double-quoted
|
||||
* YAML strings.
|
||||
*
|
||||
* @author Matthew Lewinski <matthew@lewinski.org>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class Unescaper
|
||||
{
|
||||
/**
|
||||
* Regex fragment that matches an escaped character in a double quoted string.
|
||||
*/
|
||||
public const REGEX_ESCAPED_CHARACTER = '\\\\(x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}|.)';
|
||||
|
||||
/**
|
||||
* Unescapes a single quoted string.
|
||||
*
|
||||
* @param string $value A single quoted string
|
||||
*/
|
||||
public function unescapeSingleQuotedString(string $value): string
|
||||
{
|
||||
return str_replace('\'\'', '\'', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescapes a double quoted string.
|
||||
*
|
||||
* @param string $value A double quoted string
|
||||
*/
|
||||
public function unescapeDoubleQuotedString(string $value): string
|
||||
{
|
||||
$callback = function ($match) {
|
||||
return $this->unescapeCharacter($match[0]);
|
||||
};
|
||||
|
||||
// evaluate the string
|
||||
return preg_replace_callback('/'.self::REGEX_ESCAPED_CHARACTER.'/u', $callback, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescapes a character that was found in a double-quoted string.
|
||||
*
|
||||
* @param string $value An escaped character
|
||||
*/
|
||||
private function unescapeCharacter(string $value): string
|
||||
{
|
||||
return match ($value[1]) {
|
||||
'0' => "\x0",
|
||||
'a' => "\x7",
|
||||
'b' => "\x8",
|
||||
't' => "\t",
|
||||
"\t" => "\t",
|
||||
'n' => "\n",
|
||||
'v' => "\xB",
|
||||
'f' => "\xC",
|
||||
'r' => "\r",
|
||||
'e' => "\x1B",
|
||||
' ' => ' ',
|
||||
'"' => '"',
|
||||
'/' => '/',
|
||||
'\\' => '\\',
|
||||
// U+0085 NEXT LINE
|
||||
'N' => "\xC2\x85",
|
||||
// U+00A0 NO-BREAK SPACE
|
||||
'_' => "\xC2\xA0",
|
||||
// U+2028 LINE SEPARATOR
|
||||
'L' => "\xE2\x80\xA8",
|
||||
// U+2029 PARAGRAPH SEPARATOR
|
||||
'P' => "\xE2\x80\xA9",
|
||||
'x' => self::utf8chr(hexdec(substr($value, 2, 2))),
|
||||
'u' => self::utf8chr(hexdec(substr($value, 2, 4))),
|
||||
'U' => self::utf8chr(hexdec(substr($value, 2, 8))),
|
||||
default => throw new ParseException(sprintf('Found unknown escape character "%s".', $value)),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the UTF-8 character for the given code point.
|
||||
*/
|
||||
private static function utf8chr(int $c): string
|
||||
{
|
||||
if (0x80 > $c %= 0x200000) {
|
||||
return \chr($c);
|
||||
}
|
||||
if (0x800 > $c) {
|
||||
return \chr(0xC0 | $c >> 6).\chr(0x80 | $c & 0x3F);
|
||||
}
|
||||
if (0x10000 > $c) {
|
||||
return \chr(0xE0 | $c >> 12).\chr(0x80 | $c >> 6 & 0x3F).\chr(0x80 | $c & 0x3F);
|
||||
}
|
||||
|
||||
return \chr(0xF0 | $c >> 18).\chr(0x80 | $c >> 12 & 0x3F).\chr(0x80 | $c >> 6 & 0x3F).\chr(0x80 | $c & 0x3F);
|
||||
}
|
||||
}
|
1
src/ncc/ThirdParty/Symfony/Yaml/VERSION
vendored
Normal file
1
src/ncc/ThirdParty/Symfony/Yaml/VERSION
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
6.1.3
|
96
src/ncc/ThirdParty/Symfony/Yaml/Yaml.php
vendored
Normal file
96
src/ncc/ThirdParty/Symfony/Yaml/Yaml.php
vendored
Normal file
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace ncc\ThirdParty\Symfony\Yaml;
|
||||
|
||||
use ncc\ThirdParty\Symfony\Yaml\Exception\ParseException;
|
||||
|
||||
/**
|
||||
* Yaml offers convenience methods to load and dump YAML.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class Yaml
|
||||
{
|
||||
public const DUMP_OBJECT = 1;
|
||||
public const PARSE_EXCEPTION_ON_INVALID_TYPE = 2;
|
||||
public const PARSE_OBJECT = 4;
|
||||
public const PARSE_OBJECT_FOR_MAP = 8;
|
||||
public const DUMP_EXCEPTION_ON_INVALID_TYPE = 16;
|
||||
public const PARSE_DATETIME = 32;
|
||||
public const DUMP_OBJECT_AS_MAP = 64;
|
||||
public const DUMP_MULTI_LINE_LITERAL_BLOCK = 128;
|
||||
public const PARSE_CONSTANT = 256;
|
||||
public const PARSE_CUSTOM_TAGS = 512;
|
||||
public const DUMP_EMPTY_ARRAY_AS_SEQUENCE = 1024;
|
||||
public const DUMP_NULL_AS_TILDE = 2048;
|
||||
|
||||
/**
|
||||
* Parses a YAML file into a PHP value.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* $array = Yaml::parseFile('config.yml');
|
||||
* print_r($array);
|
||||
*
|
||||
* @param string $filename The path to the YAML file to be parsed
|
||||
* @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior
|
||||
*
|
||||
* @throws ParseException If the file could not be read or the YAML is not valid
|
||||
*/
|
||||
public static function parseFile(string $filename, int $flags = 0): mixed
|
||||
{
|
||||
$yaml = new Parser();
|
||||
|
||||
return $yaml->parseFile($filename, $flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses YAML into a PHP value.
|
||||
*
|
||||
* Usage:
|
||||
* <code>
|
||||
* $array = Yaml::parse(file_get_contents('config.yml'));
|
||||
* print_r($array);
|
||||
* </code>
|
||||
*
|
||||
* @param string $input A string containing YAML
|
||||
* @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior
|
||||
*
|
||||
* @throws ParseException If the YAML is not valid
|
||||
*/
|
||||
public static function parse(string $input, int $flags = 0): mixed
|
||||
{
|
||||
$yaml = new Parser();
|
||||
|
||||
return $yaml->parse($input, $flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps a PHP value to a YAML string.
|
||||
*
|
||||
* The dump method, when supplied with an array, will do its best
|
||||
* to convert the array into friendly YAML.
|
||||
*
|
||||
* @param mixed $input The PHP value
|
||||
* @param int $inline The level where you switch to inline YAML
|
||||
* @param int $indent The amount of spaces to use for indentation of nested nodes
|
||||
* @param int $flags A bit field of DUMP_* constants to customize the dumped YAML string
|
||||
*/
|
||||
public static function dump(mixed $input, int $inline = 2, int $indent = 4, int $flags = 0): string
|
||||
{
|
||||
$yaml = new Dumper($indent);
|
||||
|
||||
return $yaml->dump($input, $inline, 0, $flags);
|
||||
}
|
||||
}
|
|
@ -1,282 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\ThirdParty\austinhyde\IniParser;
|
||||
/**
|
||||
* [MIT Licensed](http://www.opensource.org/licenses/mit-license.php)
|
||||
* Copyright (c) 2013 Austin Hyde
|
||||
*
|
||||
* Implements a parser for INI files that supports
|
||||
* * Section inheritance
|
||||
* * Property nesting
|
||||
* * Simple arrays
|
||||
*
|
||||
* Compatible with PHP 5.2.0+
|
||||
*
|
||||
* @author Austin Hyde
|
||||
* @author Till Klampaeckel <till@php.net>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,247 +0,0 @@
|
|||
# IniParser
|
||||
|
||||
[](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
|
||||
```
|
|
@ -1 +0,0 @@
|
|||
1.0.0
|
|
@ -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 . 'Symfony' . DIRECTORY_SEPARATOR . 'Yaml' . DIRECTORY_SEPARATOR . 'autoload_spl.php',
|
||||
];
|
||||
|
||||
foreach($target_files as $file)
|
||||
|
|
|
@ -28,8 +28,8 @@
|
|||
"package_name": "Filesystem"
|
||||
},
|
||||
{
|
||||
"vendor": "austinhyde",
|
||||
"package_name": "IniParser"
|
||||
"vendor": "Symfony",
|
||||
"package_name": "Yaml"
|
||||
}
|
||||
],
|
||||
"update_source": null
|
||||
|
|
Loading…
Add table
Reference in a new issue