@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1#!/usr/bin/env php
2<?php
3
4if (function_exists('pcntl_async_signals')) {
5 pcntl_async_signals(true);
6} else {
7 declare(ticks = 1);
8}
9
10require_once dirname(__FILE__).'/../../__init_script__.php';
11
12if (!posix_isatty(STDOUT)) {
13 $sid = posix_setsid();
14 if ($sid <= 0) {
15 throw new Exception(pht('Failed to create new process session!'));
16 }
17}
18
19$args = new PhutilArgumentParser($argv);
20$args->setTagline(pht('daemon executor'));
21$args->setSynopsis(pht(<<<EOHELP
22**exec_daemon.php** [__options__] __daemon__ ...
23 Run an instance of __daemon__.
24EOHELP
25 ));
26$args->parse(
27 array(
28 array(
29 'name' => 'trace',
30 'help' => pht('Enable debug tracing.'),
31 ),
32 array(
33 'name' => 'trace-memory',
34 'help' => pht('Enable debug memory tracing.'),
35 ),
36 array(
37 'name' => 'verbose',
38 'help' => pht('Enable verbose activity logging.'),
39 ),
40 array(
41 'name' => 'label',
42 'short' => 'l',
43 'param' => 'label',
44 'help' => pht(
45 'Optional process label. Makes "%s" nicer, no behavioral effects.',
46 'ps'),
47 ),
48 array(
49 'name' => 'daemon',
50 'wildcard' => true,
51 ),
52 ));
53
54$trace_memory = $args->getArg('trace-memory');
55$trace_mode = $args->getArg('trace') || $trace_memory;
56$verbose = $args->getArg('verbose');
57
58if (function_exists('posix_isatty') && posix_isatty(STDIN)) {
59 fprintf(STDERR, pht('Reading daemon configuration from stdin...')."\n");
60}
61$config = @file_get_contents('php://stdin');
62$config = id(new PhutilJSONParser())->parse($config);
63
64PhutilTypeSpec::checkMap(
65 $config,
66 array(
67 'log' => 'optional string|null',
68 'argv' => 'optional list<wild>',
69 'load' => 'optional list<string>',
70 'down' => 'optional int',
71 ));
72
73$log = idx($config, 'log');
74
75if ($log) {
76 ini_set('error_log', $log);
77 PhutilErrorHandler::setErrorListener(array('PhutilDaemon', 'errorListener'));
78}
79
80$load = idx($config, 'load', array());
81foreach ($load as $library) {
82 $library = Filesystem::resolvePath($library);
83 phutil_load_library($library);
84}
85
86PhutilErrorHandler::initialize();
87
88$daemon = $args->getArg('daemon');
89if (!$daemon) {
90 throw new PhutilArgumentUsageException(
91 pht('Specify which class of daemon to start.'));
92} else if (count($daemon) > 1) {
93 throw new PhutilArgumentUsageException(
94 pht('Specify exactly one daemon to start.'));
95} else {
96 $daemon = head($daemon);
97 if (!class_exists($daemon)) {
98 throw new PhutilArgumentUsageException(
99 pht(
100 'No class "%s" exists in any known library.',
101 $daemon));
102 } else if (!is_subclass_of($daemon, PhutilDaemon::class)) {
103 throw new PhutilArgumentUsageException(
104 pht(
105 'Class "%s" is not a subclass of "%s".',
106 $daemon,
107 'PhutilDaemon'));
108 }
109}
110
111$argv = idx($config, 'argv', array());
112$daemon = newv($daemon, array($argv));
113
114if ($trace_mode) {
115 $daemon->setTraceMode();
116}
117
118if ($trace_memory) {
119 $daemon->setTraceMemory();
120}
121
122if ($verbose) {
123 $daemon->setVerbose(true);
124}
125
126$down_duration = idx($config, 'down');
127if ($down_duration) {
128 $daemon->setScaledownDuration($down_duration);
129}
130
131$daemon->execute();