Multiple fixes
* PDO shell improvements: .query command, -r and --db on command line to read commands from file or preselect database. * Updated build scripts and readme
This commit is contained in:
parent
16753e1892
commit
0c7fc0196a
@ -1,5 +1,10 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ ! -f spark.phar ]; then
|
||||||
|
echo "error: No spark.phar has been built yet?"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
VERSION="$(git describe --tags)"
|
VERSION="$(git describe --tags)"
|
||||||
PATH="$PWD/tools:$PATH"
|
PATH="$PWD/tools:$PATH"
|
||||||
|
|
||||||
@ -16,9 +21,6 @@ echo " DESTINATION=$DESTINATION"
|
|||||||
echo "* Preparing release direcory"
|
echo "* Preparing release direcory"
|
||||||
mkdir -p $DESTINATION
|
mkdir -p $DESTINATION
|
||||||
|
|
||||||
echo "* Building phar archive"
|
|
||||||
pharlite &>/dev/null
|
|
||||||
|
|
||||||
echo "* Copying files to release directory"
|
echo "* Copying files to release directory"
|
||||||
cp spark.phar $DESTINATION/spark.phar
|
cp spark.phar $DESTINATION/spark.phar
|
||||||
cp README.md $DESTINATION/README.md
|
cp README.md $DESTINATION/README.md
|
||||||
|
5
.spark/build/phar.sh
Executable file
5
.spark/build/phar.sh
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "* Building phar archive"
|
||||||
|
pharlite &>/dev/null
|
||||||
|
|
@ -1,5 +1,13 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ ! -d .git ]; then
|
||||||
|
if [ ! -f src/version ]; then
|
||||||
|
echo -e "<?php define(\"APP_VERSION\", \"unknown\");" > src/version
|
||||||
|
echo -e "* Version: \e[1munknown\e[0m"
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
VERSION="$(git describe --tags)"
|
VERSION="$(git describe --tags)"
|
||||||
|
|
||||||
if [ -z "$VERSION" ]; then
|
if [ -z "$VERSION" ]; then
|
||||||
|
@ -4,14 +4,18 @@
|
|||||||
".spark/local/*"
|
".spark/local/*"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"version": [
|
"check-version": [
|
||||||
".spark/build/update-version.sh"
|
".spark/build/update-version.sh"
|
||||||
],
|
],
|
||||||
"package": [
|
"package": [
|
||||||
".spark/build/package.sh"
|
".spark/build/package.sh"
|
||||||
],
|
],
|
||||||
|
"phar": [
|
||||||
|
".spark/build/phar.sh"
|
||||||
|
],
|
||||||
"build": [
|
"build": [
|
||||||
"@version",
|
"@check-version",
|
||||||
|
"@phar",
|
||||||
"@package"
|
"@package"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
47
README.md
47
README.md
@ -5,10 +5,14 @@ database migrations and project deployment.
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
~~Download `spark.phar` and make it executable. If desired, alias `spark=spark.phar`.~~
|
System Requirements:
|
||||||
~~You may also want to alias `sparksh='spark repl'`.~~
|
|
||||||
|
|
||||||
Download the latest release from [dev.noccylabs.info](https://dev.noccylabs.info/noccy/php-spark/releases)
|
* PHP 8.0 or later (php-cli)
|
||||||
|
* Linux or other POSIX compatible OS. Probably. May work on MacOS!
|
||||||
|
|
||||||
|
### From dist package
|
||||||
|
|
||||||
|
Download the latest dist release from [dev.noccylabs.info](https://dev.noccylabs.info/noccy/php-spark/releases)
|
||||||
and extract it into a directory somewhere, such as `/tmp`:
|
and extract it into a directory somewhere, such as `/tmp`:
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -28,6 +32,43 @@ the `sparkplug`, `sparker`, `sparkres` and `sparksh` aliases. You can then
|
|||||||
install any new plugins into `~/opt/spark/plugins` and enable them in your
|
install any new plugins into `~/opt/spark/plugins` and enable them in your
|
||||||
projects with `sparkplug --enable the.plugin.name`.
|
projects with `sparkplug --enable the.plugin.name`.
|
||||||
|
|
||||||
|
### From installer
|
||||||
|
|
||||||
|
Download the latest installer release (the one that ends in `.run`)
|
||||||
|
from [dev.noccylabs.info](https://dev.noccylabs.info/noccy/php-spark/releases)
|
||||||
|
and make it executable:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ chmod +x spark-0.1.0-dist.run
|
||||||
|
$ ./spark-0.1.0-dist.run
|
||||||
|
```
|
||||||
|
|
||||||
|
Follow the instructions, select Yes when prompted to proceed with the installation.
|
||||||
|
|
||||||
|
### From source
|
||||||
|
|
||||||
|
Download the latest source release from [dev.noccylabs.info](https://dev.noccylabs.info/noccy/php-spark/releases)
|
||||||
|
and extract it into a directory somewhere, such as `~/src/spark`. You can then build spark, using spark:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ unzip -d ~/src/spark spark-0.1.0-src.zip
|
||||||
|
$ cd ~/src/spark
|
||||||
|
$ bin/spark run build
|
||||||
|
```
|
||||||
|
|
||||||
|
You can now install `spark.phar` where desired, and place the `plugins` directory in
|
||||||
|
a good place. You want to add the following to your `.bashrc` or similar:
|
||||||
|
|
||||||
|
```
|
||||||
|
export SPARK_PLUGINS="<path-to-plugins-dir>"
|
||||||
|
# If you don't want to rename the .phar for some reason. Skip otherwise!
|
||||||
|
alias spark=spark.phar
|
||||||
|
# Useful aliases
|
||||||
|
alias sparksh=spark repl
|
||||||
|
alias sparkplug=spark plugins
|
||||||
|
alias sparkpipe=spark pipe
|
||||||
|
```
|
||||||
|
|
||||||
## Using Spark
|
## Using Spark
|
||||||
|
|
||||||
### The easy way
|
### The easy way
|
||||||
|
@ -15,12 +15,29 @@ class PdoShellCommand extends Command {
|
|||||||
protected function configure() {
|
protected function configure() {
|
||||||
$this->setName("pdo:shell");
|
$this->setName("pdo:shell");
|
||||||
$this->setDescription("Launch an interactive PDO shell");
|
$this->setDescription("Launch an interactive PDO shell");
|
||||||
|
|
||||||
|
$this->addOption("db", null, InputOption::VALUE_REQUIRED, "Select database resource", "db");
|
||||||
|
$this->addOption("read", "r", InputOption::VALUE_REQUIRED, "Read commands to execute from file");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
{
|
{
|
||||||
$shell = new Shell\PdoShell($output);
|
$shell = new Shell\PdoShell($output);
|
||||||
$shell->run();
|
|
||||||
|
$db = $input->getOption("db");
|
||||||
|
$read = $input->getOption("read");
|
||||||
|
|
||||||
|
if ($read) {
|
||||||
|
if (!file_exists($read)) {
|
||||||
|
$output->writeln("<error>File not found: {$read}</>");
|
||||||
|
return Command::FAILURE;
|
||||||
|
}
|
||||||
|
$file = file($read, FILE_IGNORE_NEW_LINES);
|
||||||
|
$shell->runCommands($file);
|
||||||
|
} else {
|
||||||
|
$shell->runCommands([ ".select {$db}" ]);
|
||||||
|
$shell->run();
|
||||||
|
}
|
||||||
|
|
||||||
return Command::SUCCESS;
|
return Command::SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ class PdoShell {
|
|||||||
private array $defaultOptions = [
|
private array $defaultOptions = [
|
||||||
'output' => 'table',
|
'output' => 'table',
|
||||||
'table.maxwidth' => 40,
|
'table.maxwidth' => 40,
|
||||||
|
'table.style' => 'box',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function __construct(OutputInterface $output)
|
public function __construct(OutputInterface $output)
|
||||||
@ -38,7 +39,7 @@ class PdoShell {
|
|||||||
|
|
||||||
private function promptForCommand()
|
private function promptForCommand()
|
||||||
{
|
{
|
||||||
$prompt = sprintf("PDO:[%s%s]> ", $this->resource, $this->db?"":"*");
|
$prompt = sprintf("PDO:[%s%s]> ", $this->resource, $this->db?"":"?");
|
||||||
$input = readline($prompt);
|
$input = readline($prompt);
|
||||||
|
|
||||||
return $input;
|
return $input;
|
||||||
@ -81,6 +82,18 @@ class PdoShell {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function runCommands(array $commands)
|
||||||
|
{
|
||||||
|
foreach ($commands as $input) {
|
||||||
|
if (str_starts_with($input, ".")) {
|
||||||
|
[$cmd,$args] = $this->parseCommand($input);
|
||||||
|
$this->handleCommand($cmd, $args);
|
||||||
|
} else {
|
||||||
|
$this->doQuery($input, []);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function handleCommand(string $command, array $args)
|
private function handleCommand(string $command, array $args)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -94,9 +107,14 @@ class PdoShell {
|
|||||||
case '.var':
|
case '.var':
|
||||||
$this->doVarCommand($args);
|
$this->doVarCommand($args);
|
||||||
break;
|
break;
|
||||||
|
case '.query':
|
||||||
|
$this->doQueryCommand($args);
|
||||||
|
break;
|
||||||
case '.help':
|
case '.help':
|
||||||
$this->doHelpCommand($args);
|
$this->doHelpCommand($args);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case '.quit':
|
||||||
case '.exit':
|
case '.exit':
|
||||||
$this->running = false;
|
$this->running = false;
|
||||||
break;;
|
break;;
|
||||||
@ -112,8 +130,9 @@ class PdoShell {
|
|||||||
'.select RES' => "Select the database resource to query",
|
'.select RES' => "Select the database resource to query",
|
||||||
'.set [KEY [VALUE]]' => "Set a configuration value",
|
'.set [KEY [VALUE]]' => "Set a configuration value",
|
||||||
'.var [NAME [VALUE]]' => "Set a variable, or show variable value",
|
'.var [NAME [VALUE]]' => "Set a variable, or show variable value",
|
||||||
'.exit' => "Exit the shell",
|
'.exit|.quit' => "Exit the shell",
|
||||||
'SQL' => "Run SQL against the database",
|
'SQL' => "Run SQL against the database",
|
||||||
|
'.query SQL [PARAM..]' => "Escape and run a query using ? as placeholder",
|
||||||
];
|
];
|
||||||
foreach ($cmds as $cmd=>$info) {
|
foreach ($cmds as $cmd=>$info) {
|
||||||
$this->output->writeln(" <options=bold>{$cmd}</> - <info>{$info}</>");
|
$this->output->writeln(" <options=bold>{$cmd}</> - <info>{$info}</>");
|
||||||
@ -150,7 +169,7 @@ class PdoShell {
|
|||||||
if ($res instanceof PdoResource) {
|
if ($res instanceof PdoResource) {
|
||||||
$this->db = $res;
|
$this->db = $res;
|
||||||
$this->resource = $name;
|
$this->resource = $name;
|
||||||
$this->output->writeln("<fg=green>Seleced {$name}</>");
|
$this->output->writeln("<fg=green>** Selected {$name}</>");
|
||||||
} else {
|
} else {
|
||||||
$this->output->writeln("<error>Invalid resource {$name}</>");
|
$this->output->writeln("<error>Invalid resource {$name}</>");
|
||||||
}
|
}
|
||||||
@ -176,8 +195,17 @@ class PdoShell {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function doQueryCommand(array $args)
|
||||||
|
{
|
||||||
|
$query = array_shift($args);
|
||||||
|
$this->doQuery($query, $args);
|
||||||
|
}
|
||||||
|
|
||||||
private function doQuery(string $query, array $params=[])
|
private function doQuery(string $query, array $params=[])
|
||||||
{
|
{
|
||||||
|
if (!$query) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!$this->db) {
|
if (!$this->db) {
|
||||||
$this->output->writeln("<error>No database resource selected</>");
|
$this->output->writeln("<error>No database resource selected</>");
|
||||||
return;
|
return;
|
||||||
@ -210,7 +238,7 @@ class PdoShell {
|
|||||||
if (count($res) == 0) return;
|
if (count($res) == 0) return;
|
||||||
$table = new Table($this->output);
|
$table = new Table($this->output);
|
||||||
$table->setHeaders(array_keys(reset($res)));
|
$table->setHeaders(array_keys(reset($res)));
|
||||||
|
$table->setStyle($this->options['table.style']);
|
||||||
$max = $this->options['table.maxwidth'];
|
$max = $this->options['table.maxwidth'];
|
||||||
|
|
||||||
foreach ($res as $row) {
|
foreach ($res as $row) {
|
||||||
|
@ -47,47 +47,6 @@ class Environment
|
|||||||
return $runner;
|
return $runner;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
public function runScript(string $name, array $args, InputInterface $input, OutputInterface $output)
|
|
||||||
{
|
|
||||||
$script = $this->config['scripts'][$name]??$name;
|
|
||||||
|
|
||||||
if (is_string($script)) {
|
|
||||||
$this->execScript($script, $args, $output);
|
|
||||||
} elseif (is_array($script)) {
|
|
||||||
foreach ($script as $row) {
|
|
||||||
$a = str_getcsv($row, ' ', "'");
|
|
||||||
$c = array_shift($a);
|
|
||||||
if (str_starts_with($c, '@')) {
|
|
||||||
$c = ($this->config['scripts'][substr($c,1)])??$c;
|
|
||||||
$this->runScript($c, $a, $input, $output);
|
|
||||||
} else {
|
|
||||||
$this->execScript($c, $a, $output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function execScript(string $script, array $args, OutputInterface $output)
|
|
||||||
{
|
|
||||||
// call script directly
|
|
||||||
if (str_ends_with($script, '.php')) {
|
|
||||||
$GLOBALS['args'] = $args;
|
|
||||||
$GLOBALS['output'] = $output;
|
|
||||||
$base = $this->getProjectDirectory();
|
|
||||||
if (!file_exists($base ."/". $script)) {
|
|
||||||
fprintf(STDERR, "error: Could not find script file %s\n", $base."/".$script);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//echo "# ".$base."/".$script."\n";
|
|
||||||
include $base . "/" . $script;
|
|
||||||
} else {
|
|
||||||
//echo "$ {$script}\n";
|
|
||||||
passthru($script);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
public function loadEnvironment()
|
public function loadEnvironment()
|
||||||
{
|
{
|
||||||
if ($this->loaded) {
|
if ($this->loaded) {
|
||||||
@ -135,7 +94,7 @@ class Environment
|
|||||||
try {
|
try {
|
||||||
include_once($item);
|
include_once($item);
|
||||||
} catch (\Throwable $t) {
|
} catch (\Throwable $t) {
|
||||||
fprintf(STDERR, "error: Error preloading %s: %s in %s on line %d\n", $item, $t->getMessage(), $t->getFile(), $t->getLine());
|
fprintf(STDERR, "warning: Error preloading %s: %s in %s on line %d\n", $item, $t->getMessage(), $t->getFile(), $t->getLine());
|
||||||
//$this->logger->error("Error preloading {$item}: {$t->getMessage()} in {$t->getFile()} on line {$t->getLine()}");
|
//$this->logger->error("Error preloading {$item}: {$t->getMessage()} in {$t->getFile()} on line {$t->getLine()}");
|
||||||
}
|
}
|
||||||
} elseif (is_dir($item) && file_exists($item."/sparkplug.php")) {
|
} elseif (is_dir($item) && file_exists($item."/sparkplug.php")) {
|
||||||
@ -143,7 +102,7 @@ class Environment
|
|||||||
try {
|
try {
|
||||||
include_once($item."/sparkplug.php");
|
include_once($item."/sparkplug.php");
|
||||||
} catch (\Throwable $t) {
|
} catch (\Throwable $t) {
|
||||||
fprintf(STDERR, "error: Error preloading plugin %s: %s in %s on line %d\n", $item, $t->getMessage(), $t->getFile(), $t->getLine());
|
fprintf(STDERR, "warning: Error preloading plugin %s: %s in %s on line %d\n", $item, $t->getMessage(), $t->getFile(), $t->getLine());
|
||||||
//$this->logger->error("Error preloading plugin {$item}: {$t->getMessage()} in {$t->getFile()} on line {$t->getLine()}");
|
//$this->logger->error("Error preloading plugin {$item}: {$t->getMessage()} in {$t->getFile()} on line {$t->getLine()}");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -174,9 +133,9 @@ class Environment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function createFromDirectory(string|null $directory=null, bool $parents=false): Environment
|
public static function createFromDirectory(string|null $directory=null, bool $parents=false): ?Environment
|
||||||
{
|
{
|
||||||
$directory = $directory ?? getcwd();
|
$directory = realpath($directory) ?? getcwd();
|
||||||
|
|
||||||
if ($parents) {
|
if ($parents) {
|
||||||
$check = $directory;
|
$check = $directory;
|
||||||
@ -190,7 +149,7 @@ class Environment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$candidates = [ $directory . "/.spark.json", $directory . "/.spark/spark.json" ];
|
$candidates = [ $directory . "/.spark.json", $directory . "/spark.json", $directory . "/.spark/spark.json" ];
|
||||||
$config = [];
|
$config = [];
|
||||||
while ($candidate = array_shift($candidates)) {
|
while ($candidate = array_shift($candidates)) {
|
||||||
if (!file_exists($candidate)) { continue; }
|
if (!file_exists($candidate)) { continue; }
|
||||||
@ -205,6 +164,9 @@ class Environment
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$config) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
$env = new Environment($config);
|
$env = new Environment($config);
|
||||||
|
|
||||||
return $env;
|
return $env;
|
||||||
|
Loading…
Reference in New Issue
Block a user