diff --git a/apps/dav/appinfo/info.xml b/apps/dav/appinfo/info.xml
index 10f78d8332a2b..0295529dd26f9 100644
--- a/apps/dav/appinfo/info.xml
+++ b/apps/dav/appinfo/info.xml
@@ -50,7 +50,6 @@
OCA\DAV\Command\CreateCalendar
OCA\DAV\Command\DeleteCalendar
OCA\DAV\Command\MoveCalendar
- OCA\DAV\Command\ListCalendars
OCA\DAV\Command\RetentionCleanupCommand
OCA\DAV\Command\SendEventReminders
OCA\DAV\Command\SyncBirthdayCalendar
diff --git a/apps/dav/lib/AppInfo/Application.php b/apps/dav/lib/AppInfo/Application.php
index 580918a645008..f3ed664941738 100644
--- a/apps/dav/lib/AppInfo/Application.php
+++ b/apps/dav/lib/AppInfo/Application.php
@@ -52,6 +52,7 @@
use OCA\DAV\CardDAV\ContactsManager;
use OCA\DAV\CardDAV\PhotoCache;
use OCA\DAV\CardDAV\SyncService;
+use OCA\DAV\Command\ListCalendars;
use OCA\DAV\Events\AddressBookCreatedEvent;
use OCA\DAV\Events\AddressBookDeletedEvent;
use OCA\DAV\Events\AddressBookShareUpdatedEvent;
@@ -122,6 +123,11 @@ public function register(IRegistrationContext $context): void {
*/
$context->registerCapability(Capabilities::class);
+ /**
+ * Register commands
+ */
+ $context->registerCommand(ListCalendars::class);
+
/*
* Register Search Providers
*/
diff --git a/apps/dav/lib/Command/ListCalendars.php b/apps/dav/lib/Command/ListCalendars.php
index 35581c2d4b21e..e9436544e8962 100644
--- a/apps/dav/lib/Command/ListCalendars.php
+++ b/apps/dav/lib/Command/ListCalendars.php
@@ -1,4 +1,7 @@
userManager = $userManager;
$this->caldav = $caldav;
}
- protected function configure() {
- $this
- ->setName('dav:list-calendars')
- ->setDescription('List all calendars of a user')
- ->addArgument('uid',
- InputArgument::REQUIRED,
- 'User for whom all calendars will be listed');
+ public function getName(): string {
+ return 'list-calendars';
+ }
+
+ public function getDescription(): string {
+ return 'List all calendars of a user';
+ }
+
+ public function configure(IConfiguration $configuration): void {
+ $configuration->addArgument(
+ 'uid',
+ true,
+ 'User for whom all calendars will be listed'
+ );
}
- protected function execute(InputInterface $input, OutputInterface $output): int {
+ public function execute(IInput $input, IOutput $output): int {
$user = $input->getArgument('uid');
if (!$this->userManager->userExists($user)) {
throw new \InvalidArgumentException("User <$user> is unknown.");
@@ -92,11 +98,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}
if (count($calendarTableData) > 0) {
- $table = new Table($output);
- $table->setHeaders(['uri', 'displayname', 'owner\'s userid', 'owner\'s displayname', 'writable'])
- ->setRows($calendarTableData);
+ //$table = new Table($output);
+ //$table->setHeaders(['uri', 'displayname', 'owner\'s userid', 'owner\'s displayname', 'writable'])
+ // ->setRows($calendarTableData);
- $table->render();
+ //$table->render();
} else {
$output->writeln("User <$user> has no calendars");
}
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index f12ee47642af9..15e0ec73589c7 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -150,8 +150,12 @@
'OCP\\Collaboration\\Resources\\IResource' => $baseDir . '/lib/public/Collaboration/Resources/IResource.php',
'OCP\\Collaboration\\Resources\\LoadAdditionalScriptsEvent' => $baseDir . '/lib/public/Collaboration/Resources/LoadAdditionalScriptsEvent.php',
'OCP\\Collaboration\\Resources\\ResourceException' => $baseDir . '/lib/public/Collaboration/Resources/ResourceException.php',
+ 'OCP\\Command\\Command' => $baseDir . '/lib/public/Command/Command.php',
'OCP\\Command\\IBus' => $baseDir . '/lib/public/Command/IBus.php',
'OCP\\Command\\ICommand' => $baseDir . '/lib/public/Command/ICommand.php',
+ 'OCP\\Command\\IConfiguration' => $baseDir . '/lib/public/Command/IConfiguration.php',
+ 'OCP\\Command\\IInput' => $baseDir . '/lib/public/Command/IInput.php',
+ 'OCP\\Command\\IOutput' => $baseDir . '/lib/public/Command/IOutput.php',
'OCP\\Comments\\CommentsEntityEvent' => $baseDir . '/lib/public/Comments/CommentsEntityEvent.php',
'OCP\\Comments\\CommentsEvent' => $baseDir . '/lib/public/Comments/CommentsEvent.php',
'OCP\\Comments\\IComment' => $baseDir . '/lib/public/Comments/IComment.php',
@@ -827,6 +831,10 @@
'OC\\Command\\CronBus' => $baseDir . '/lib/private/Command/CronBus.php',
'OC\\Command\\FileAccess' => $baseDir . '/lib/private/Command/FileAccess.php',
'OC\\Command\\QueueBus' => $baseDir . '/lib/private/Command/QueueBus.php',
+ 'OC\\Command\\SymfonyCommandAdapter' => $baseDir . '/lib/private/Command/SymfonyCommandAdapter.php',
+ 'OC\\Command\\SymfonyConfigurationAdapter' => $baseDir . '/lib/private/Command/SymfonyConfigurationAdapter.php',
+ 'OC\\Command\\SymfonyInputAdapter' => $baseDir . '/lib/private/Command/SymfonyInputAdapter.php',
+ 'OC\\Command\\SymfonyOutputAdapter' => $baseDir . '/lib/private/Command/SymfonyOutputAdapter.php',
'OC\\Comments\\Comment' => $baseDir . '/lib/private/Comments/Comment.php',
'OC\\Comments\\Manager' => $baseDir . '/lib/private/Comments/Manager.php',
'OC\\Comments\\ManagerFactory' => $baseDir . '/lib/private/Comments/ManagerFactory.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index 502556d3f7fb5..cdfe44613ad61 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -183,8 +183,12 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Collaboration\\Resources\\IResource' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Resources/IResource.php',
'OCP\\Collaboration\\Resources\\LoadAdditionalScriptsEvent' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Resources/LoadAdditionalScriptsEvent.php',
'OCP\\Collaboration\\Resources\\ResourceException' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Resources/ResourceException.php',
+ 'OCP\\Command\\Command' => __DIR__ . '/../../..' . '/lib/public/Command/Command.php',
'OCP\\Command\\IBus' => __DIR__ . '/../../..' . '/lib/public/Command/IBus.php',
'OCP\\Command\\ICommand' => __DIR__ . '/../../..' . '/lib/public/Command/ICommand.php',
+ 'OCP\\Command\\IConfiguration' => __DIR__ . '/../../..' . '/lib/public/Command/IConfiguration.php',
+ 'OCP\\Command\\IInput' => __DIR__ . '/../../..' . '/lib/public/Command/IInput.php',
+ 'OCP\\Command\\IOutput' => __DIR__ . '/../../..' . '/lib/public/Command/IOutput.php',
'OCP\\Comments\\CommentsEntityEvent' => __DIR__ . '/../../..' . '/lib/public/Comments/CommentsEntityEvent.php',
'OCP\\Comments\\CommentsEvent' => __DIR__ . '/../../..' . '/lib/public/Comments/CommentsEvent.php',
'OCP\\Comments\\IComment' => __DIR__ . '/../../..' . '/lib/public/Comments/IComment.php',
@@ -860,6 +864,10 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Command\\CronBus' => __DIR__ . '/../../..' . '/lib/private/Command/CronBus.php',
'OC\\Command\\FileAccess' => __DIR__ . '/../../..' . '/lib/private/Command/FileAccess.php',
'OC\\Command\\QueueBus' => __DIR__ . '/../../..' . '/lib/private/Command/QueueBus.php',
+ 'OC\\Command\\SymfonyCommandAdapter' => __DIR__ . '/../../..' . '/lib/private/Command/SymfonyCommandAdapter.php',
+ 'OC\\Command\\SymfonyConfigurationAdapter' => __DIR__ . '/../../..' . '/lib/private/Command/SymfonyConfigurationAdapter.php',
+ 'OC\\Command\\SymfonyInputAdapter' => __DIR__ . '/../../..' . '/lib/private/Command/SymfonyInputAdapter.php',
+ 'OC\\Command\\SymfonyOutputAdapter' => __DIR__ . '/../../..' . '/lib/private/Command/SymfonyOutputAdapter.php',
'OC\\Comments\\Comment' => __DIR__ . '/../../..' . '/lib/private/Comments/Comment.php',
'OC\\Comments\\Manager' => __DIR__ . '/../../..' . '/lib/private/Comments/Manager.php',
'OC\\Comments\\ManagerFactory' => __DIR__ . '/../../..' . '/lib/private/Comments/ManagerFactory.php',
diff --git a/lib/private/AppFramework/Bootstrap/RegistrationContext.php b/lib/private/AppFramework/Bootstrap/RegistrationContext.php
index 7b4d24036e80d..2117f31e984e9 100644
--- a/lib/private/AppFramework/Bootstrap/RegistrationContext.php
+++ b/lib/private/AppFramework/Bootstrap/RegistrationContext.php
@@ -32,6 +32,7 @@
use Closure;
use OCP\Calendar\Resource\IBackend as IResourceBackend;
use OCP\Calendar\Room\IBackend as IRoomBackend;
+use OCP\Command\Command;
use OCP\Talk\ITalkBackend;
use RuntimeException;
use function array_shift;
@@ -61,6 +62,9 @@ class RegistrationContext {
/** @var ServiceRegistration[] */
private $capabilities = [];
+ /** @var ServiceRegistration[] */
+ private $commands = [];
+
/** @var ServiceRegistration[] */
private $crashReporters = [];
@@ -151,6 +155,13 @@ public function registerCapability(string $capability): void {
);
}
+ public function registerCommand(string $command): void {
+ $this->context->registerCommand(
+ $this->appId,
+ $command
+ );
+ }
+
public function registerCrashReporter(string $reporterClass): void {
$this->context->registerCrashReporter(
$this->appId,
@@ -314,6 +325,13 @@ public function registerCapability(string $appId, string $capability): void {
$this->capabilities[] = new ServiceRegistration($appId, $capability);
}
+ /**
+ * @psalm-param class-string $capability
+ */
+ public function registerCommand(string $appId, string $command): void {
+ $this->commands[] = new ServiceRegistration($appId, $command);
+ }
+
/**
* @psalm-param class-string $capability
*/
@@ -612,6 +630,13 @@ public function delegateMiddlewareRegistrations(array $apps): void {
}
}
+ /**
+ * @return ServiceRegistration[]
+ */
+ public function getCommands(): array {
+ return $this->commands;
+ }
+
/**
* @return ServiceRegistration[]
*/
diff --git a/lib/private/Command/SymfonyCommandAdapter.php b/lib/private/Command/SymfonyCommandAdapter.php
new file mode 100644
index 0000000000000..a0385a3ca15f4
--- /dev/null
+++ b/lib/private/Command/SymfonyCommandAdapter.php
@@ -0,0 +1,59 @@
+
+ *
+ * @author 2022 Christoph Wurst
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+namespace OC\Command;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class SymfonyCommandAdapter extends Command {
+
+ private \OCP\Command\Command $command;
+
+ public function __construct(\OCP\Command\Command $command) {
+ $this->command = $command;
+
+ parent::__construct($command->getFullyQualifiedName());
+ }
+
+ protected function configure() {
+ parent::configure();
+
+ $this->setDescription($this->command->getDescription());
+
+ $this->command->configure(
+ new SymfonyConfigurationAdapter($this)
+ );
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $this->command->execute(
+ new SymfonyInputAdapter($input),
+ new SymfonyOutputAdapter($output)
+ );
+ }
+
+}
diff --git a/lib/private/Command/SymfonyConfigurationAdapter.php b/lib/private/Command/SymfonyConfigurationAdapter.php
new file mode 100644
index 0000000000000..88575be572643
--- /dev/null
+++ b/lib/private/Command/SymfonyConfigurationAdapter.php
@@ -0,0 +1,52 @@
+
+ *
+ * @author 2022 Christoph Wurst
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+namespace OC\Command;
+
+use OCP\Command\IConfiguration;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+
+class SymfonyConfigurationAdapter implements IConfiguration {
+
+ private Command $command;
+
+ public function __construct(Command $command) {
+ $this->command = $command;
+ }
+
+ public function addArgument(string $name,
+ bool $required = false,
+ string $description = '',
+ $default = null): void {
+ $this->command->addArgument(
+ $name,
+ $required ? InputArgument::REQUIRED : InputArgument::OPTIONAL,
+ $description,
+ $default
+ );
+ }
+
+}
diff --git a/lib/private/Command/SymfonyInputAdapter.php b/lib/private/Command/SymfonyInputAdapter.php
new file mode 100644
index 0000000000000..e1c9df3a4260b
--- /dev/null
+++ b/lib/private/Command/SymfonyInputAdapter.php
@@ -0,0 +1,47 @@
+
+ *
+ * @author 2022 Christoph Wurst
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+namespace OC\Command;
+
+use OCP\Command\IInput;
+use Symfony\Component\Console\Input\InputInterface;
+
+class SymfonyInputAdapter implements IInput {
+
+ private InputInterface $input;
+
+ public function __construct(InputInterface $input) {
+ $this->input = $input;
+ }
+
+ public function isInteractive(): bool {
+ return $this->input->isInteractive();
+ }
+
+ public function getArgument(string $name) {
+ return $this->input->getArgument($name);
+ }
+
+}
diff --git a/lib/private/Command/SymfonyOutputAdapter.php b/lib/private/Command/SymfonyOutputAdapter.php
new file mode 100644
index 0000000000000..e4a641742b05a
--- /dev/null
+++ b/lib/private/Command/SymfonyOutputAdapter.php
@@ -0,0 +1,50 @@
+
+ *
+ * @author 2022 Christoph Wurst
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+namespace OC\Command;
+
+use OCP\Command\IOutput;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class SymfonyOutputAdapter implements IOutput {
+
+ private OutputInterface $output;
+
+ public function __construct(OutputInterface $output) {
+ $this->output = $output;
+ }
+
+ public function formatError(string $message): string {
+ return '' . $message . '';
+ }
+
+ public function formatInfo(string $message): string {
+ return '' . $message . '';
+ }
+
+ public function writeLn(string $message): void {
+ $this->output->writeln($message);
+ }
+}
diff --git a/lib/private/Console/Application.php b/lib/private/Console/Application.php
index 12d54b48fa97e..bb3efd470fea2 100644
--- a/lib/private/Console/Application.php
+++ b/lib/private/Console/Application.php
@@ -30,6 +30,8 @@
*/
namespace OC\Console;
+use OC\AppFramework\Bootstrap\Coordinator;
+use OC\Command\SymfonyCommandAdapter;
use OC\MemoryInfo;
use OC\NeedsUpdateException;
use OC_App;
@@ -44,6 +46,7 @@
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Throwable;
class Application {
/** @var IConfig */
@@ -140,6 +143,21 @@ public function loadCommands(
}
}
}
+ /** @var Coordinator $coordinator */
+ $coordinator = \OC::$server->get(Coordinator::class);
+ $registrationContext = $coordinator->getRegistrationContext();
+ foreach ($registrationContext->getCommands() as $commandRegistration) {
+ try {
+ $command = \OC::$server->get($commandRegistration->getService());
+ $adapter = new SymfonyCommandAdapter($command);
+ $this->application->add($adapter);
+ } catch (Throwable $e) {
+ $this->logger->error("Could not load command: " . $e->getMessage(), [
+ 'exception' => $e,
+ 'app' => $commandRegistration->getAppId(),
+ ]);
+ }
+ }
}
} elseif ($input->getArgument('command') !== '_completion' && $input->getArgument('command') !== 'maintenance:install') {
$errorOutput = $output->getErrorOutput();
diff --git a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php
index a5d675f14c74c..171537993e447 100644
--- a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php
+++ b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php
@@ -56,6 +56,8 @@ interface IRegistrationContext {
*/
public function registerCapability(string $capability): void;
+ public function registerCommand(string $command): void;
+
/**
* Register an implementation of \OCP\Support\CrashReport\IReporter that
* will receive unhandled exceptions and throwables
diff --git a/lib/public/Command/Command.php b/lib/public/Command/Command.php
new file mode 100644
index 0000000000000..2f20e3e37c3aa
--- /dev/null
+++ b/lib/public/Command/Command.php
@@ -0,0 +1,69 @@
+
+ *
+ * @author 2022 Christoph Wurst
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+namespace OCP\Command;
+
+use function implode;
+
+abstract class Command {
+
+ public const EXIT_CODE_SUCCESS = 0;
+ public const EXIT_CODE_ERROR = 1;
+
+ private string $appId;
+
+ public function __construct(string $appId) {
+ $this->appId = $appId;
+ }
+
+ public function getNamespace(): ?string {
+ return $this->appId;
+ }
+
+ public abstract function getName(): string;
+
+ public abstract function getDescription(): string;
+
+ public function getFullyQualifiedName(): string {
+ if ($this->getNamespace() === null) {
+ return $this->getName();
+ }
+
+ return implode(':', [
+ $this->getNamespace(),
+ $this->getName()
+ ]);
+ }
+
+ public function isEnabled(): bool {
+ return true;
+ }
+
+ public function configure(IConfiguration $config): void {
+ }
+
+ public abstract function execute(IInput $input, IOutput $output);
+
+}
diff --git a/lib/public/Command/IConfiguration.php b/lib/public/Command/IConfiguration.php
new file mode 100644
index 0000000000000..1aa3406e8ae10
--- /dev/null
+++ b/lib/public/Command/IConfiguration.php
@@ -0,0 +1,35 @@
+
+ *
+ * @author 2022 Christoph Wurst
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+namespace OCP\Command;
+
+interface IConfiguration {
+
+ public function addArgument(string $name,
+ bool $required = false,
+ string $description = '',
+ $default = null): void;
+
+}
diff --git a/lib/public/Command/IInput.php b/lib/public/Command/IInput.php
new file mode 100644
index 0000000000000..b6c4e4744b4cf
--- /dev/null
+++ b/lib/public/Command/IInput.php
@@ -0,0 +1,37 @@
+
+ *
+ * @author 2022 Christoph Wurst
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+namespace OCP\Command;
+
+interface IInput {
+
+ public function isInteractive(): bool;
+
+ /**
+ * @return mixed
+ */
+ public function getArgument(string $name);
+
+}
diff --git a/lib/public/Command/IOutput.php b/lib/public/Command/IOutput.php
new file mode 100644
index 0000000000000..d55cb784f278c
--- /dev/null
+++ b/lib/public/Command/IOutput.php
@@ -0,0 +1,36 @@
+
+ *
+ * @author 2022 Christoph Wurst
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+namespace OCP\Command;
+
+interface IOutput {
+
+ public function formatError(string $message): string;
+
+ public function formatInfo(string $message): string;
+
+ public function writeLn(string $message): void;
+
+}