Many changes

This commit is contained in:
Netkas 2023-02-23 16:22:20 -05:00
parent 085cb5a24c
commit 56561bca05
7 changed files with 364 additions and 88 deletions

View file

@ -10,6 +10,7 @@
use RuntimeException;
use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Yaml\Yaml;
class Configuration
{
@ -57,7 +58,6 @@
// Figure out the path to the configuration file
try
{
/** @noinspection PhpUndefinedClassInspection */
$this->Path = Runtime::getDataPath('net.nosial.configlib') . DIRECTORY_SEPARATOR . $name . '.conf';
}
catch (Exception $e)
@ -232,8 +232,6 @@
{
if(!self::validateKey($key))
return false;
if(!isset($this->Configuration[$key]))
return false;
$path = explode('.', $key);
$current = $this->Configuration;
@ -281,6 +279,7 @@
try
{
$fs->dumpFile($this->Path, $json);
$fs->chmod($this->Path, 0777);
}
catch (IOException $e)
{
@ -356,6 +355,11 @@
return $this->Configuration;
}
public function toYaml(): string
{
return Yaml::dump($this->Configuration, 4, 2);
}
/**
* Public Destructor
*/
@ -373,4 +377,38 @@
}
}
}
/**
* Imports a YAML file into the configuration
*
* @param string $path
* @return void
* @throws Exception
*/
public function import(string $path)
{
$fs = new Filesystem();
if(!$fs->exists($path))
throw new Exception(sprintf('Unable to import configuration file "%s", file does not exist', $path));
$yaml = file_get_contents($path);
$data = Yaml::parse($yaml);
$this->Configuration = array_replace_recursive($this->Configuration, $data);
$this->Modified = true;
}
/**
* Exports the configuration to a YAML file
*
* @param string $path
* @return void
*/
public function export(string $path)
{
$fs = new Filesystem();
$fs->dumpFile($path, $this->toYaml());
$fs->chmod($path, 0777);
}
}

View file

@ -3,9 +3,17 @@
namespace ConfigLib;
use Exception;
use JetBrains\PhpStorm\NoReturn;
use ncc\Exceptions\InvalidPackageNameException;
use ncc\Exceptions\InvalidScopeException;
use ncc\Exceptions\PackageLockException;
use ncc\Exceptions\PackageNotFoundException;
use ncc\Runtime;
use OptsLib\Parse;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Process\Process;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml;
class Program
{
@ -14,22 +22,21 @@
*
* @return void
*/
public static function main(): void
#[NoReturn] public static function main(): void
{
$args = Parse::getArguments();
if(isset($args['help']) || isset($args['h']))
self::help();
if(isset($args['version']) || isset($args['v']))
self::version();
if(isset($args['name']) || isset($args['n']))
if(isset($args['conf']) || isset($args['config']))
{
$configuration_name = $args['name'] ?? $args['n'] ?? null;
$property = $args['property'] ?? $args['p'] ?? null;
$value = $args['value'] ?? $args['v'] ?? null;
$editor = $args['editor'] ?? $args['e'] ?? null;
$configuration_name = $args['conf'] ?? $args['config'] ?? null;
$property = $args['prop'] ?? $args['property'] ?? null;
$value = $args['val'] ?? $args['value'] ?? null;
$editor = $args['editor'] ?? @$args['e'] ?? null;
$export = $args['export'] ?? null;
$import = $args['import'] ?? null;
if($configuration_name === null)
{
@ -39,21 +46,71 @@
$configuration = new Configuration($configuration_name);
// Check if the configuration exists first.
if(!file_exists($configuration->getPath()))
{
print(sprintf('Configuration \'%s\' does not exist, aborting' . PHP_EOL, $configuration->getName()));
exit(1);
}
if($import !== null)
{
try
{
$configuration->import((string)$import);
$configuration->save();
}
catch (Exception $e)
{
print($e->getMessage() . PHP_EOL);
exit(1);
}
print(sprintf('Configuration \'%s\' imported from \'%s\'' . PHP_EOL, $configuration->getName(), $import));
exit(0);
}
if($export !== null)
{
if(!is_string($export))
$export = sprintf('%s.yml', $configuration->getName());
try
{
$configuration->export($export);
}
catch (Exception $e)
{
print($e->getMessage() . PHP_EOL);
exit(1);
}
print(sprintf('Configuration \'%s\' exported to \'%s\'' . PHP_EOL, $configuration->getName(), $export));
exit(0);
}
if($editor !== null)
{
self::edit($args);
return;
try
{
self::edit($args, $configuration);
}
catch(Exception $e)
{
print($e->getMessage() . PHP_EOL);
exit(1);
}
}
if($property === null)
{
print(json_encode($configuration->getConfiguration(), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . PHP_EOL);
print($configuration->toYaml() . PHP_EOL);
}
else
{
if($value === null)
{
print(json_encode($configuration->get($property, '(not set)'), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . PHP_EOL);
print(Yaml::dump($configuration->get($property), 4, 2) . PHP_EOL);
return;
}
@ -81,25 +138,27 @@
*
* @return void
*/
private static function help(): void
#[NoReturn] private static function help(): void
{
print('ConfigLib v' . Runtime::getConstant('net.nosial.configlib', 'version') . PHP_EOL . PHP_EOL);
print('Usage: configlib [options]' . PHP_EOL);
print(' -h, --help Displays the help menu' . PHP_EOL);
print(' -v, --version Displays the version of the program' . PHP_EOL);
print(' -n, --name <name> The name of the configuration' . PHP_EOL);
print(' -p, --path <path> The property name to select/read (eg; foo.bar.baz) (Inline)' . PHP_EOL);
print(' -v, --value <value> The value to set the property (Inline)' . PHP_EOL);
print(' -e, --editor <editor> (Optional) The editor to use (eg; nano, vim, notepad) (External)' . PHP_EOL);
print(' --nc (Optional) Disables type casting (eg; \'true\' > True) will always be a string' . PHP_EOL);
print(' --export <file> (Optional) Exports the configuration to a file' . PHP_EOL);
print(' --import <file> (Optional) Imports the configuration from a file' . PHP_EOL);
print('Examples:' . PHP_EOL);
print(' configlib -n com.example.package' . PHP_EOL);
print(' configlib -n com.example.package -e nano' . PHP_EOL);
print(' configlib -n com.example.package -p foo.bar.baz -v 123' . PHP_EOL);
print(' configlib -n com.example.package -p foo.bar.baz -v 123 --nc' . PHP_EOL);
print(' configlib -n com.example.package --export config.json' . PHP_EOL);
print(' configlib -n com.example.package --import config.json' . PHP_EOL);
print(' -h, --help Displays the help menu' . PHP_EOL);
print(' --conf, --config <name> The name of the configuration' . PHP_EOL);
print(' --prop, --property <property> The property name to select/read (eg; foo.bar.baz) (Inline)' . PHP_EOL);
print(' --val, --value <value> The value to set the property (Inline)' . PHP_EOL);
print(' -e, --editor <editor> (Optional) The editor to use (eg; nano, vim, notepad) (External)' . PHP_EOL);
print(' --export <file> (Optional) Exports the configuration to a file' . PHP_EOL);
print(' --import <file> (Optional) Imports the configuration from a file' . PHP_EOL);
print(' --nc (Optional) Disables type casting (eg; \'true\' > True) will always be a string' . PHP_EOL);
print('Examples:' . PHP_EOL . PHP_EOL);
print(' configlib --conf test View the configuration' . PHP_EOL);
print(' configlib --conf test --prop foo View a specific property' . PHP_EOL);
print(' configlib --conf test --prop foo --val bar Set a specific property' . PHP_EOL);
print(' configlib --conf test --editor nano Edit the configuration' . PHP_EOL);
print(' configlib --conf test --export out.json Export the configuration' . PHP_EOL);
print(' configlib --conf test --import in.json Import a configuration' . PHP_EOL);
exit(0);
}
@ -108,16 +167,19 @@
* Edits an existing configuration file or creates a new one if it doesn't exist
*
* @param array $args
* @param Configuration $configuration
* @return void
* @throws InvalidPackageNameException
* @throws InvalidScopeException
* @throws PackageLockException
* @throws PackageNotFoundException
*/
private static function edit(array $args): void
#[NoReturn] static function edit(array $args, Configuration $configuration): void
{
$editor = $args['editor'] ?? 'vi';
if(isset($args['e']))
$editor = $args['e'];
$name = $args['name'] ?? 'default';
if($editor == null)
{
print('No editor specified' . PHP_EOL);
@ -125,21 +187,25 @@
}
// Determine the temporary path to use
$tempPath = null;
if(function_exists('ini_get'))
if(file_exists(DIRECTORY_SEPARATOR . 'tmp'))
{
$tempPath = ini_get('upload_tmp_dir');
if($tempPath == null)
$tempPath = ini_get('session.save_path');
if($tempPath == null)
$tempPath = ini_get('upload_tmp_dir');
if($tempPath == null)
$tempPath = sys_get_temp_dir();
$tempPath = DIRECTORY_SEPARATOR . 'tmp';
}
else
{
if(!file_exists(Runtime::getDataPath('net.nosial.configlib') . DIRECTORY_SEPARATOR . 'tmp'))
{
mkdir(Runtime::getDataPath('net.nosial.configlib') . DIRECTORY_SEPARATOR . 'tmp', 0777, true);
if($tempPath == null && function_exists('sys_get_temp_dir'))
$tempPath = sys_get_temp_dir();
if(!file_exists(Runtime::getDataPath('net.nosial.configlib') . DIRECTORY_SEPARATOR . 'tmp'))
{
print('Unable to create the temporary path to use' . PHP_EOL);
exit(1);
}
}
$tempPath = Runtime::getDataPath('net.nosial.configlib') . DIRECTORY_SEPARATOR . 'tmp';
}
if($tempPath == null)
{
@ -147,26 +213,16 @@
exit(1);
}
// Prepare the temporary file
try
{
$configuration = new Configuration($name);
}
catch (Exception $e)
{
print($e->getMessage() . PHP_EOL);
exit(1);
}
$fs = new Filesystem();
$tempFile = $tempPath . DIRECTORY_SEPARATOR . $name . '.conf';
$fs->copy($configuration->getPath(), $tempFile);
// Convert the configuration from JSON to YAML for editing purposes
$tempFile = $tempPath . DIRECTORY_SEPARATOR . bin2hex(random_bytes(16)) . '.yaml';
$fs->dumpFile($tempFile, $configuration->toYaml());
$original_hash = hash_file('sha1', $tempFile);
// Open the editor
try
{
// Open the editor
$process = new Process([$editor, $tempFile]);
$process->setTimeout(0);
$process->setTty(true);
@ -177,10 +233,6 @@
print('Unable to open the editor, ' . $e->getMessage() . PHP_EOL);
exit(1);
}
finally
{
$fs->remove($tempFile);
}
// Check if the file has changed and if so, update the configuration
if($fs->exists($tempFile))
@ -188,26 +240,29 @@
$new_hash = hash_file('sha1', $tempFile);
if($original_hash != $new_hash)
{
$fs->copy($tempFile, $configuration->getPath());
}
else
{
print('No changes detected' . PHP_EOL);
}
// Convert the YAML back to JSON
$yaml = file_get_contents($tempFile);
$fs->remove($tempFile);
try
{
$json = Yaml::parse($yaml);
}
catch (ParseException $e)
{
print('Unable to parse the YAML file, ' . $e->getMessage() . PHP_EOL);
exit(1);
}
$path = $configuration->getPath();
$fs->dumpFile($path, json_encode($json, JSON_PRETTY_PRINT));
print('Configuration updated' . PHP_EOL);
}
}
}
// Remove the temporary file
if($fs->exists($tempFile))
$fs->remove($tempFile);
/**
* Prints out the version of the program
*
* @return void
*/
private static function version(): void
{
print('ConfigLib v1.0.0' . PHP_EOL);
exit(0);
}
}