Passed
Pull Request — master (#9)
by Shinji
01:19
created

DaemonCommand::configure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 58
Code Lines 48

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 48
c 1
b 0
f 1
nc 1
nop 0
dl 0
loc 58
rs 9.1344

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * This file is part of the sj-i/php-profiler package.
5
 *
6
 * (c) sji <[email protected]>
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
declare(strict_types=1);
13
14
namespace PhpProfiler\Command\Inspector;
15
16
use Amp\Loop;
0 ignored issues
show
Bug introduced by
The type Amp\Loop was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
use Amp\Promise;
0 ignored issues
show
Bug introduced by
The type Amp\Promise was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
18
use Amp\Parallel\Context;
0 ignored issues
show
Bug introduced by
The type Amp\Parallel\Context was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
use PhpProfiler\Command\Inspector\Settings\DaemonSettings;
20
use PhpProfiler\Command\Inspector\Settings\GetTraceSettings;
21
use PhpProfiler\Command\Inspector\Settings\TargetPhpSettings;
22
use PhpProfiler\Command\Inspector\Settings\TraceLoopSettings;
23
use Symfony\Component\Console\Command\Command;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Command\Command was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
24
use Symfony\Component\Console\Input\InputInterface;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Input\InputInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
25
use Symfony\Component\Console\Input\InputOption;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Input\InputOption was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
26
use Symfony\Component\Console\Output\OutputInterface;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Output\OutputInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
27
28
final class DaemonCommand extends Command
29
{
30
    public function configure(): void
31
    {
32
        $this->setName('inspector:daemon')
33
            ->setDescription('periodically get running function name from an outer process or thread')
34
            ->addOption(
35
                'target-regex',
36
                'P',
37
                InputOption::VALUE_OPTIONAL,
38
                'regex to find the php binary loaded in the target process'
39
            )
40
            ->addOption('depth', 'd', InputOption::VALUE_OPTIONAL, 'max depth')
41
            ->addOption(
42
                'sleep-ns',
43
                's',
44
                InputOption::VALUE_OPTIONAL,
45
                'nanoseconds between traces (default: 1000 * 1000 * 10)'
46
            )
47
            ->addOption(
48
                'max-retries',
49
                'r',
50
                InputOption::VALUE_OPTIONAL,
51
                'max retries on contiguous errors of read (default: 10)'
52
            )
53
            ->addOption(
54
                'threads',
55
                'T',
56
                InputOption::VALUE_OPTIONAL,
57
                'number of workers (default: 8)'
58
            )
59
            ->addOption(
60
                'php-regex',
61
                null,
62
                InputOption::VALUE_OPTIONAL,
63
                'regex to find the php binary loaded in the target process'
64
            )
65
            ->addOption(
66
                'libpthread-regex',
67
                null,
68
                InputOption::VALUE_OPTIONAL,
69
                'regex to find the libpthread.so loaded in the target process'
70
            )
71
            ->addOption(
72
                'php-version',
73
                null,
74
                InputOption::VALUE_OPTIONAL,
75
                'php version of the target'
76
            )
77
            ->addOption(
78
                'php-path',
79
                null,
80
                InputOption::VALUE_OPTIONAL,
81
                'path to the php binary (only needed in tracing chrooted ZTS target)'
82
            )
83
            ->addOption(
84
                'libpthread-path',
85
                null,
86
                InputOption::VALUE_OPTIONAL,
87
                'path to the libpthread.so (only needed in tracing chrooted ZTS target)'
88
            )
89
        ;
90
    }
91
92
    /**
93
     * @param InputInterface $input
94
     * @param OutputInterface $output
95
     * @return int
96
     */
97
    public function execute(InputInterface $input, OutputInterface $output): int
98
    {
99
        $target_php_settings = TargetPhpSettings::fromConsoleInput($input);
100
        $loop_settings = TraceLoopSettings::fromConsoleInput($input);
101
        $get_trace_settings = GetTraceSettings::fromConsoleInput($input);
102
        $daemon_settings = DaemonSettings::fromConsoleInput($input);
103
104
        $context = Context\create(__DIR__ . '/Worker/php-searcher.php');
0 ignored issues
show
Bug introduced by
The function create was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

104
        $context = /** @scrutinizer ignore-call */ Context\create(__DIR__ . '/Worker/php-searcher.php');
Loading history...
105
        /** @var int $searcher_pid */
106
        $searcher_pid = Promise\wait($context->start());
0 ignored issues
show
Bug introduced by
The function wait was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

106
        $searcher_pid = /** @scrutinizer ignore-call */ Promise\wait($context->start());
Loading history...
Unused Code introduced by
The assignment to $searcher_pid is dead and can be removed.
Loading history...
107
        Promise\wait($context->send($daemon_settings->target_regex));
108
        /** @var int[] $pid_list */
109
        $pid_list = Promise\wait($context->receive());
110
        $readers = [];
111
        foreach ($pid_list as $target_pid) {
112
            $context = Context\create(__DIR__ . '/Worker/php-reader.php');
113
            Promise\wait($context->start());
114
            Promise\wait($context->send([$target_pid, $target_php_settings, $loop_settings, $get_trace_settings]));
115
            $readers[$target_pid] = $context;
116
        }
117
        exec('stty -icanon -echo');
118
119
        Loop::run(function () use (&$readers, $output) {
120
            Loop::onReadable(
121
                STDIN,
122
                /** @param resource $stream */
123
                function (string $watcher_id, $stream) {
124
                    $key = fread($stream, 1);
125
                    if ($key === 'q') {
126
                        Loop::cancel($watcher_id);
127
                        Loop::stop();
128
                    }
129
                }
130
            );
131
            Loop::repeat(10, function () use (&$readers, $output) {
132
                /** @var array<int, Context\Context> $readers */
133
134
                $promises = [];
135
                foreach ($readers as $pid => $reader) {
136
                    if (!$reader->isRunning()) {
137
                        /** @psalm-suppress MixedArrayAccess*/
138
                        unset($readers[$pid]);
139
                        continue;
140
                    }
141
                    $promises[] = \Amp\call(
0 ignored issues
show
Bug introduced by
The function call was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

141
                    $promises[] = /** @scrutinizer ignore-call */ \Amp\call(
Loading history...
142
                        function () use ($reader, &$readers, $pid, $output) {
143
                            /** @psalm-suppress MixedArrayAccess*/
144
                            unset($readers[$pid]);
145
                            /** @var string $result */
146
                            $result = yield $reader->receive();
147
                            $output->write($result);
148
                            $readers[$pid] = $reader;
149
                        }
150
                    );
151
                }
152
                yield $promises;
153
            });
154
        });
155
156
        return 0;
157
    }
158
}
159