diff --git a/appinfo/info.xml b/appinfo/info.xml
index b936471..de5c977 100755
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -43,6 +43,7 @@ Allows administrators to write small scripts which users can run through the fil
OCA\FilesScripts\Command\ListScripts
OCA\FilesScripts\Command\ImportScripts
OCA\FilesScripts\Command\ExportScripts
+ OCA\FilesScripts\Command\Interactive
OCA\FilesScripts\Settings\AdminSettings
diff --git a/docs/Admin.md b/docs/Admin.md
index 82ebf65..9de42af 100644
--- a/docs/Admin.md
+++ b/docs/Admin.md
@@ -88,3 +88,16 @@ To get the `` value, you can use the user-list command:
```sh
occ user:list
```
+
+## Interactive (REPL) shell
+You can start an interactive shell with the `files_scripts:interactive` command
+```sh
+occ files_scripts:interactive
+```
+
+Multi-line commands can be given by ending the line with a backslash character:
+```
+> print("hello \
+> world")
+```
+You can type the `exit` command to exit the shell.
diff --git a/lib/Command/Interactive.php b/lib/Command/Interactive.php
new file mode 100644
index 0000000..22ba9ee
--- /dev/null
+++ b/lib/Command/Interactive.php
@@ -0,0 +1,90 @@
+rootFolder = $rootFolder;
+ $this->luaProvider = $luaProvider;
+ $this->interpreter = $interpreter;
+ }
+ protected function configure(): void {
+ $this->setDescription('Starts an interactive Lua shell where you can interact with the server using the scripting API')
+ ->addOption('user', 'u', InputOption::VALUE_OPTIONAL, 'User as which the action should be run')
+ ->addOption('file', 'f', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'File path or id of a file given to the action as input file');
+
+ parent::configure();
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int {
+ $userId = $input->getOption('user');
+ $rootFolder = $this->rootFolder;
+
+ try {
+ if ($userId) {
+ $rootFolder = $this->rootFolder->getUserFolder($userId);
+ }
+ $files = RunScript::getFilesForCommand($input, $output, $rootFolder);
+ } catch (\Throwable $e) {
+ $output->writeln('' . $e->getMessage() .'');
+ return 1;
+ }
+
+ $output->writeln('Lua files_scripts interpreter started...');
+ $output->writeln('To stop type "exit"');
+
+ $context = new Context($this->luaProvider->createLua(), $rootFolder, [], $files);
+ $f = fopen( 'php://stdin', 'r' );
+ $command = "";
+ while (true) {
+ echo "> ";
+ $line = fgets( $f );
+
+ // Handle exit clause
+ if (trim($line) == "exit") {
+ fclose($f);
+ break;
+ }
+
+ $replacements = 0;
+ $line = preg_replace('/(.*)\\\\(\s*)$/i', '$1 $2', $line, 1, $replacements);
+ $command .= $line;
+
+ // if line does not end with `\` backslash we execute the command
+ if ($replacements == 0) {
+ $this->executeCommand($command, $context, $output);
+ $command = "";
+ }
+ }
+
+ return 0;
+ }
+
+ private function executeCommand(string $command, Context $context, OutputInterface $output): void {
+ $script = new Script();
+ $script->setProgram($command);
+ try {
+ $this->interpreter->execute($script, $context);
+ } catch (\Throwable $e) {
+ $output->writeln('' . $e->getMessage() . '');
+ }
+ }
+}
diff --git a/lib/Command/RunScript.php b/lib/Command/RunScript.php
index 5876833..e639334 100644
--- a/lib/Command/RunScript.php
+++ b/lib/Command/RunScript.php
@@ -1,12 +1,14 @@
getArgument('id');
- $userId = $input->getOption('user');
- $scriptInputsJson = $input->getOption('inputs') ?? '{}';
+ public static function getFilesForCommand(InputInterface $input, OutputInterface $output, Folder $rootFolder) {
$fileInputs = $input->getOption('file') ?? [];
-
- try {
- $scriptInputsData = json_decode($scriptInputsJson, true, 512, JSON_THROW_ON_ERROR);
- } catch (\JsonException $err) {
- $output->writeln('Could not parse the inputs JSON');
- return 1;
- }
-
- $script = $this->scriptMapper->find($scriptId);
- $output->writeln('Executing file action: ' . $script->getTitle() . '');
-
- $scriptInputs = $this->scriptInputMapper->findAllByScriptId($scriptId);
- foreach ($scriptInputs as $scriptInput) {
- $value = $scriptInputsData[$scriptInput->getName()] ?? null;
- $scriptInput->setValue($value);
- }
-
- $rootFolder = $this->rootFolder->getUserFolder($userId);
$files = [];
$n = 1;
@@ -77,22 +58,56 @@ protected function execute(InputInterface $input, OutputInterface $output) {
if (ctype_digit(strval($fileInput))) {
$nodes = $rootFolder->getById(intval($fileInput));
if (!isset($nodes[0])) {
- $output->writeln('Could not find input file ' . $fileInput . ' belonging in root folder ' . $rootFolder->getPath() . ' for file action');
- return 1;
+ throw new Error('Could not find input file ' . $fileInput . ' belonging in root folder ' . $rootFolder->getPath() . ' for file action');
}
$file = $nodes[0];
unset($nodes);
} else {
$file = $rootFolder->get($fileInput);
}
- } catch (\Exception $e) {
- $output->writeln('Could not find input file ' . $fileInput . ' belonging in root folder ' . $rootFolder->getPath() . ' for file action');
- return 1;
+ } catch (\Throwable $e) {
+ throw $e;
}
$files[$n++] = $file;
}
}
+ return $files;
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $scriptId = $input->getArgument('id');
+ $userId = $input->getOption('user');
+ $scriptInputsJson = $input->getOption('inputs') ?? '{}';
+
+ try {
+ $scriptInputsData = json_decode($scriptInputsJson, true, 512, JSON_THROW_ON_ERROR);
+ } catch (\JsonException $err) {
+ $output->writeln('Could not parse the inputs JSON');
+ return 1;
+ }
+
+ $script = $this->scriptMapper->find($scriptId);
+ $output->writeln('Executing file action: ' . $script->getTitle() . '');
+
+ $scriptInputs = $this->scriptInputMapper->findAllByScriptId($scriptId) ?? [];
+ foreach ($scriptInputs as $scriptInput) {
+ $value = $scriptInputsData[$scriptInput->getName()] ?? null;
+ $scriptInput->setValue($value);
+ }
+
+ $rootFolder = $this->rootFolder;
+ try {
+ if ($userId) {
+ $rootFolder = $this->rootFolder->getUserFolder($userId);
+ }
+ $files = self::getFilesForCommand($input, $output, $rootFolder);
+ } catch (\Throwable $e) {
+ $output->writeln('' . $e->getMessage() .'');
+ return 1;
+ }
+
+ print(gettype($scriptInputs));
$context = new Context(
$this->luaProvider->createLua(),
$rootFolder,
diff --git a/lib/Interpreter/RegistrableFunction.php b/lib/Interpreter/RegistrableFunction.php
index 5c94fb0..cf060c2 100755
--- a/lib/Interpreter/RegistrableFunction.php
+++ b/lib/Interpreter/RegistrableFunction.php
@@ -52,7 +52,7 @@ final protected function getHomeFolder(): Folder {
return $folder;
}
- final protected function getPath(array $data): string {
+ final protected function getPath(?array $data): string {
return ($data['path'] ?? '') . '/' . ($data['name'] ?? '');
}