Subversion-Projekte lars-tiefland.laravel_shop

Revision

Revision 148 | Details | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
/*
4
 * This file is part of Psy Shell.
5
 *
200 lars 6
 * (c) 2012-2023 Justin Hileman
148 lars 7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
 
12
namespace Psy\Output;
13
 
14
use Symfony\Component\Console\Output\StreamOutput;
15
 
16
/**
17
 * ProcOutputPager class.
18
 *
19
 * A ProcOutputPager instance wraps a regular StreamOutput's stream. Rather
20
 * than writing directly to the stream, it shells out to a pager process and
21
 * gives that process the stream as stdout. This means regular *nix commands
22
 * like `less` and `more` can be used to page large amounts of output.
23
 */
24
class ProcOutputPager extends StreamOutput implements OutputPager
25
{
26
    private $proc;
27
    private $pipe;
28
    private $stream;
29
    private $cmd;
30
 
31
    /**
32
     * Constructor.
33
     *
34
     * @param StreamOutput $output
35
     * @param string       $cmd    Pager process command (default: 'less -R -F -X')
36
     */
37
    public function __construct(StreamOutput $output, string $cmd = 'less -R -F -X')
38
    {
39
        $this->stream = $output->getStream();
40
        $this->cmd = $cmd;
41
    }
42
 
43
    /**
44
     * Writes a message to the output.
45
     *
46
     * @param string $message A message to write to the output
47
     * @param bool   $newline Whether to add a newline or not
48
     *
49
     * @throws \RuntimeException When unable to write output (should never happen)
50
     */
51
    public function doWrite($message, $newline)
52
    {
53
        $pipe = $this->getPipe();
54
        if (false === @\fwrite($pipe, $message.($newline ? \PHP_EOL : ''))) {
55
            // @codeCoverageIgnoreStart
56
            // should never happen
57
            $this->close();
58
            throw new \RuntimeException('Unable to write output');
59
            // @codeCoverageIgnoreEnd
60
        }
61
 
62
        \fflush($pipe);
63
    }
64
 
65
    /**
66
     * Close the current pager process.
67
     */
68
    public function close()
69
    {
70
        if (isset($this->pipe)) {
71
            \fclose($this->pipe);
72
        }
73
 
74
        if (isset($this->proc)) {
75
            $exit = \proc_close($this->proc);
76
            if ($exit !== 0) {
77
                throw new \RuntimeException('Error closing output stream');
78
            }
79
        }
80
 
81
        $this->pipe = null;
82
        $this->proc = null;
83
    }
84
 
85
    /**
86
     * Get a pipe for paging output.
87
     *
88
     * If no active pager process exists, fork one and return its input pipe.
89
     */
90
    private function getPipe()
91
    {
92
        if (!isset($this->pipe) || !isset($this->proc)) {
93
            $desc = [['pipe', 'r'], $this->stream, \fopen('php://stderr', 'w')];
94
            $this->proc = \proc_open($this->cmd, $desc, $pipes);
95
 
96
            if (!\is_resource($this->proc)) {
97
                throw new \RuntimeException('Error opening output stream');
98
            }
99
 
100
            $this->pipe = $pipes[0];
101
        }
102
 
103
        return $this->pipe;
104
    }
105
}