2023-02-23 13:11:50 -05:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace ConfigLib;
|
|
|
|
|
|
|
|
use Exception;
|
2023-02-23 16:22:20 -05:00
|
|
|
use JetBrains\PhpStorm\NoReturn;
|
|
|
|
use ncc\Exceptions\InvalidPackageNameException;
|
|
|
|
use ncc\Exceptions\InvalidScopeException;
|
|
|
|
use ncc\Exceptions\PackageLockException;
|
|
|
|
use ncc\Exceptions\PackageNotFoundException;
|
|
|
|
use ncc\Runtime;
|
2023-02-23 13:11:50 -05:00
|
|
|
use OptsLib\Parse;
|
2023-07-11 14:32:27 -04:00
|
|
|
use RuntimeException;
|
2023-02-23 13:11:50 -05:00
|
|
|
use Symfony\Component\Filesystem\Filesystem;
|
|
|
|
use Symfony\Component\Process\Process;
|
2023-02-23 16:22:20 -05:00
|
|
|
use Symfony\Component\Yaml\Exception\ParseException;
|
|
|
|
use Symfony\Component\Yaml\Yaml;
|
2023-02-23 13:11:50 -05:00
|
|
|
|
|
|
|
class Program
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Main entry point of the program
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
2023-02-23 16:22:20 -05:00
|
|
|
#[NoReturn] public static function main(): void
|
2023-02-23 13:11:50 -05:00
|
|
|
{
|
|
|
|
$args = Parse::getArguments();
|
|
|
|
|
|
|
|
if(isset($args['help']) || isset($args['h']))
|
2023-07-11 14:32:27 -04:00
|
|
|
{
|
2023-02-23 13:11:50 -05:00
|
|
|
self::help();
|
2023-07-11 14:32:27 -04:00
|
|
|
}
|
2023-02-23 13:11:50 -05:00
|
|
|
|
2023-02-23 16:22:20 -05:00
|
|
|
if(isset($args['conf']) || isset($args['config']))
|
2023-02-23 13:11:50 -05:00
|
|
|
{
|
2023-02-23 16:22:20 -05:00
|
|
|
$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;
|
2023-02-23 13:11:50 -05:00
|
|
|
|
|
|
|
if($configuration_name === null)
|
|
|
|
{
|
|
|
|
print('You must specify a configuration name' . PHP_EOL);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
$configuration = new Configuration($configuration_name);
|
|
|
|
|
2023-02-23 16:22:20 -05:00
|
|
|
// 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))
|
2023-07-11 14:32:27 -04:00
|
|
|
{
|
2023-02-23 16:22:20 -05:00
|
|
|
$export = sprintf('%s.yml', $configuration->getName());
|
2023-07-11 14:32:27 -04:00
|
|
|
}
|
2023-02-23 16:22:20 -05:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2023-02-23 13:11:50 -05:00
|
|
|
if($editor !== null)
|
|
|
|
{
|
2023-02-23 16:22:20 -05:00
|
|
|
try
|
|
|
|
{
|
|
|
|
self::edit($args, $configuration);
|
|
|
|
}
|
|
|
|
catch(Exception $e)
|
|
|
|
{
|
|
|
|
print($e->getMessage() . PHP_EOL);
|
|
|
|
exit(1);
|
|
|
|
}
|
2023-02-23 13:11:50 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if($property === null)
|
|
|
|
{
|
2023-02-23 16:22:20 -05:00
|
|
|
print($configuration->toYaml() . PHP_EOL);
|
2023-02-23 13:11:50 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if($value === null)
|
|
|
|
{
|
2023-02-23 16:22:20 -05:00
|
|
|
print(Yaml::dump($configuration->get($property), 4, 2) . PHP_EOL);
|
2023-02-23 13:11:50 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$configuration->set($property, $value);
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
$configuration->save();
|
|
|
|
}
|
|
|
|
catch (Exception $e)
|
|
|
|
{
|
|
|
|
print($e->getMessage() . PHP_EOL);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
self::help();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Prints out the Help information for the program
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
2023-02-23 16:22:20 -05:00
|
|
|
#[NoReturn] private static function help(): void
|
2023-02-23 13:11:50 -05:00
|
|
|
{
|
2023-02-23 16:22:20 -05:00
|
|
|
print('ConfigLib v' . Runtime::getConstant('net.nosial.configlib', 'version') . PHP_EOL . PHP_EOL);
|
|
|
|
|
2023-02-23 13:11:50 -05:00
|
|
|
print('Usage: configlib [options]' . PHP_EOL);
|
2023-02-23 16:22:20 -05:00
|
|
|
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);
|
2023-02-23 13:11:50 -05:00
|
|
|
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Edits an existing configuration file or creates a new one if it doesn't exist
|
|
|
|
*
|
|
|
|
* @param array $args
|
2023-02-23 16:22:20 -05:00
|
|
|
* @param Configuration $configuration
|
2023-02-23 13:11:50 -05:00
|
|
|
* @return void
|
2023-02-23 16:22:20 -05:00
|
|
|
* @throws InvalidPackageNameException
|
|
|
|
* @throws InvalidScopeException
|
|
|
|
* @throws PackageLockException
|
|
|
|
* @throws PackageNotFoundException
|
2023-02-23 13:11:50 -05:00
|
|
|
*/
|
2023-07-11 14:32:27 -04:00
|
|
|
#[NoReturn] private static function edit(array $args, Configuration $configuration): void
|
2023-02-23 13:11:50 -05:00
|
|
|
{
|
2023-07-11 14:32:27 -04:00
|
|
|
$editor = $args['editor'] ?? $args['e'] ?? 'vi';
|
2023-02-23 13:11:50 -05:00
|
|
|
|
2023-07-11 14:32:27 -04:00
|
|
|
if($editor === null)
|
2023-02-23 13:11:50 -05:00
|
|
|
{
|
|
|
|
print('No editor specified' . PHP_EOL);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determine the temporary path to use
|
2023-02-23 16:22:20 -05:00
|
|
|
if(file_exists(DIRECTORY_SEPARATOR . 'tmp'))
|
2023-02-23 13:11:50 -05:00
|
|
|
{
|
2023-02-23 16:22:20 -05:00
|
|
|
$tempPath = DIRECTORY_SEPARATOR . 'tmp';
|
2023-02-23 13:11:50 -05:00
|
|
|
}
|
2023-02-23 16:22:20 -05:00
|
|
|
else
|
2023-02-23 13:11:50 -05:00
|
|
|
{
|
2023-02-23 16:22:20 -05:00
|
|
|
if(!file_exists(Runtime::getDataPath('net.nosial.configlib') . DIRECTORY_SEPARATOR . 'tmp'))
|
|
|
|
{
|
2023-07-11 14:32:27 -04:00
|
|
|
if (!mkdir($concurrentDirectory = Runtime::getDataPath('net.nosial.configlib') . DIRECTORY_SEPARATOR . 'tmp', 0777, true) && !is_dir($concurrentDirectory))
|
|
|
|
{
|
|
|
|
throw new RuntimeException(sprintf('Directory "%s" was not created', $concurrentDirectory));
|
|
|
|
}
|
2023-02-23 13:11:50 -05:00
|
|
|
|
2023-02-23 16:22:20 -05:00
|
|
|
if(!file_exists(Runtime::getDataPath('net.nosial.configlib') . DIRECTORY_SEPARATOR . 'tmp'))
|
|
|
|
{
|
|
|
|
print('Unable to create the temporary path to use' . PHP_EOL);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
2023-02-23 13:11:50 -05:00
|
|
|
|
2023-02-23 16:22:20 -05:00
|
|
|
$tempPath = Runtime::getDataPath('net.nosial.configlib') . DIRECTORY_SEPARATOR . 'tmp';
|
2023-02-23 13:11:50 -05:00
|
|
|
}
|
2023-02-23 16:22:20 -05:00
|
|
|
|
2023-02-23 13:11:50 -05:00
|
|
|
$fs = new Filesystem();
|
2023-02-23 16:22:20 -05:00
|
|
|
|
2023-02-23 13:11:50 -05:00
|
|
|
try
|
|
|
|
{
|
2023-07-11 14:32:27 -04:00
|
|
|
// 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);
|
|
|
|
|
2023-02-23 16:22:20 -05:00
|
|
|
// Open the editor
|
2023-02-23 13:11:50 -05:00
|
|
|
$process = new Process([$editor, $tempFile]);
|
|
|
|
$process->setTimeout(0);
|
|
|
|
$process->setTty(true);
|
|
|
|
$process->run();
|
|
|
|
}
|
|
|
|
catch(Exception $e)
|
|
|
|
{
|
|
|
|
print('Unable to open the editor, ' . $e->getMessage() . PHP_EOL);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if the file has changed and if so, update the configuration
|
|
|
|
if($fs->exists($tempFile))
|
|
|
|
{
|
|
|
|
$new_hash = hash_file('sha1', $tempFile);
|
2023-07-11 14:32:27 -04:00
|
|
|
if($original_hash !== $new_hash)
|
2023-02-23 13:11:50 -05:00
|
|
|
{
|
2023-02-23 16:22:20 -05:00
|
|
|
// Convert the YAML back to JSON
|
|
|
|
$yaml = file_get_contents($tempFile);
|
2023-02-23 13:11:50 -05:00
|
|
|
|
2023-02-23 16:22:20 -05:00
|
|
|
try
|
|
|
|
{
|
|
|
|
$json = Yaml::parse($yaml);
|
|
|
|
}
|
|
|
|
catch (ParseException $e)
|
|
|
|
{
|
|
|
|
print('Unable to parse the YAML file, ' . $e->getMessage() . PHP_EOL);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2023-07-11 14:32:27 -04:00
|
|
|
try
|
|
|
|
{
|
|
|
|
$path = $configuration->getPath();
|
|
|
|
$fs->dumpFile($path, json_encode($json, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT));
|
|
|
|
}
|
|
|
|
catch(Exception $e)
|
|
|
|
{
|
|
|
|
print('Unable to save the configuration, ' . $e->getMessage() . PHP_EOL);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2023-02-23 16:22:20 -05:00
|
|
|
print('Configuration updated' . PHP_EOL);
|
|
|
|
}
|
2023-02-23 13:11:50 -05:00
|
|
|
}
|
|
|
|
|
2023-02-23 16:22:20 -05:00
|
|
|
// Remove the temporary file
|
|
|
|
if($fs->exists($tempFile))
|
2023-07-11 14:32:27 -04:00
|
|
|
{
|
2023-02-23 16:22:20 -05:00
|
|
|
$fs->remove($tempFile);
|
2023-07-11 14:32:27 -04:00
|
|
|
}
|
2023-02-23 13:11:50 -05:00
|
|
|
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
}
|