public static function exec($command, array $args = [], $cwd = null, $verbose = false): string
    {
        if (!class_exists(Process::class)) {
            throw new Exception('Symfony/Process package required for Cli::exec() method'); // @codeCoverageIgnore
        }

        $cmd = self::build($command, $args);
        /** @noinspection CallableParameterUseCaseInTypeContextInspection */
        $cwd = $cwd ? realpath($cwd) : null;

        //@codeCoverageIgnoreStart
        if ($verbose) {
            // Only in testing mode
            if (\function_exists('\JBZoo\PHPUnit\cliMessage')) {
                cliMessage('Process: ' . $cmd);
                cliMessage('CWD: ' . $cwd);
            } else {
                self::out('Process: ' . $cmd);
                self::out('CWD: ' . $cwd);
            }
        }
        //@codeCoverageIgnoreEnd

        // execute command
        try {
            if (method_exists(Process::class, 'fromShellCommandline')) {
                $process = Process::fromShellCommandline($cmd, $cwd, null, null, 3600);
            } else {
                $process = new Process($cmd, $cwd, null, null, 3600);
            }

            $process->inheritEnvironmentVariables(true);
            $process->run();
        } catch (\Exception $exception) {
            throw new Exception($exception, (int)$exception->getCode(), $exception);
        }

        // executes after the command finishes
        if (!$process->isSuccessful()) {
            throw new ProcessFailedException($process);
        }

        return $process->getOutput();
    }