Skip to content

Commit 8150385

Browse files
committed
Rework unit templates
1 parent a3cbc25 commit 8150385

32 files changed

+906
-643
lines changed

assets/unit-template.tpl

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
[Unit]
1+
<?php foreach ($sections as $section => $properties): ?>
2+
[<?= $this->e($section); ?>]
3+
<?php foreach ($properties as $property => $value): ?>
4+
<?= $this->e($property); ?>=<?= $this->e($value); ?>
5+
<?php endforeach; ?>
26

3-
[Service]
4-
5-
[Install]
7+
<?php endforeach; ?>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace SystemCtl\Exception;
4+
5+
use Throwable;
6+
7+
class PropertyNotSupportedException extends \Exception
8+
{
9+
/**
10+
* PropertyNotSupportedException constructor.
11+
* @param string $property
12+
* @param string $class
13+
* @param int $code
14+
* @param Throwable|null $previous
15+
*/
16+
public function __construct(string $property, string $class, $code = 0, Throwable $previous = null)
17+
{
18+
parent::__construct("Property '{$property}' not supported in {$class}", $code, $previous);
19+
}
20+
}

src/Exception/UnitTypeNotSupportedException.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,4 @@
44

55
class UnitTypeNotSupportedException extends \Exception
66
{
7-
87
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
3+
namespace SystemCtl\Template;
4+
5+
use SebastianBergmann\CodeCoverage\Report\Xml\Unit;
6+
use SystemCtl\Template\Section\AbstractSection;
7+
use SystemCtl\Template\Section\InstallSection;
8+
use SystemCtl\Template\Section\UnitSection;
9+
use SystemCtl\Utils\DefinitionConverter;
10+
11+
/**
12+
* AbstractUnitTemplate
13+
*
14+
* Defines basic properties for a unit
15+
*
16+
* @package SystemCtl\Template
17+
* @author icanhazstring <[email protected]>
18+
*/
19+
abstract class AbstractUnitTemplate
20+
{
21+
/** @var string */
22+
protected $name;
23+
/** @var string */
24+
protected $unitSuffix;
25+
26+
/** @var UnitSection */
27+
protected $unitSection;
28+
/** @var InstallSection */
29+
protected $installSection;
30+
31+
/**
32+
* Create a new template for any unit
33+
*
34+
* @param string $unitName
35+
* @param string $unitSuffix
36+
*/
37+
public function __construct(string $unitName, string $unitSuffix)
38+
{
39+
$this->name = $unitName;
40+
$this->unitSuffix = $unitSuffix;
41+
42+
$this->unitSection = new UnitSection;
43+
$this->installSection = new InstallSection;
44+
}
45+
46+
/**
47+
* Get all definitions for this template as array
48+
*
49+
* @return array
50+
*/
51+
public function getDefinitions(): array
52+
{
53+
$unitProperties = $this->getUnitSection()->getProperties();
54+
$installProperties = $this->getInstallSection()->getProperties();
55+
56+
$definitions = [];
57+
58+
if (!empty($unitProperties)) {
59+
$definitions['Unit'] = $this->convertProperties($unitProperties);
60+
}
61+
62+
if (!empty($installProperties)) {
63+
$definitions['Install'] = $this->convertProperties($installProperties);
64+
}
65+
66+
return $definitions;
67+
}
68+
69+
/**
70+
* Convert properties to proper definitions in templates
71+
*
72+
* @param $properties
73+
*
74+
* @return array
75+
*/
76+
protected function convertProperties($properties)
77+
{
78+
return array_map([DefinitionConverter::class, 'convert'], $properties);
79+
}
80+
81+
/**
82+
* @return string
83+
*/
84+
public function getName(): string
85+
{
86+
return $this->name;
87+
}
88+
89+
/**
90+
* @return string
91+
*/
92+
public function getUnitSuffix(): string
93+
{
94+
return $this->unitSuffix;
95+
}
96+
97+
/**
98+
* @return UnitSection
99+
*/
100+
public function getUnitSection(): UnitSection
101+
{
102+
return $this->unitSection;
103+
}
104+
105+
/**
106+
* @return InstallSection
107+
*/
108+
public function getInstallSection(): InstallSection
109+
{
110+
return $this->installSection;
111+
}
112+
}
Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
<?php
22

3-
namespace SystemCtl\Template;
3+
namespace SystemCtl\Template\Renderer;
44

55
use League\Plates;
6+
use SystemCtl\Template\RendererInterface;
7+
use SystemCtl\Template\AbstractUnitTemplate;
68

79
/**
810
* PlatesRenderer
@@ -29,8 +31,8 @@ public function __construct(Plates\Engine $engine)
2931
/**
3032
* @inheritdoc
3133
*/
32-
public function render(string $templateFile, UnitTemplate $unitTemplate): string
34+
public function render(string $templateFile, AbstractUnitTemplate $unitTemplate): string
3335
{
34-
return $this->engine->render($templateFile, ['unitTemplate' => $unitTemplate]);
36+
return $this->engine->render($templateFile, ['sections' => $unitTemplate->getDefinitions()]);
3537
}
3638
}

src/Template/RendererAwareInterface.php

Lines changed: 0 additions & 17 deletions
This file was deleted.

src/Template/RendererInterface.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ interface RendererInterface
77
/**
88
* Render a named template with given data
99
*
10-
* @param string $templateFile
11-
* @param UnitTemplate $unitTemplate
10+
* @param string $templateFile
11+
* @param AbstractUnitTemplate $unitTemplate
12+
*
1213
* @return string
1314
*/
14-
public function render(string $templateFile, UnitTemplate $unitTemplate): string;
15+
public function render(string $templateFile, AbstractUnitTemplate $unitTemplate): string;
1516
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace SystemCtl\Template\Section;
4+
5+
use SystemCtl\Exception\PropertyNotSupportedException;
6+
7+
abstract class AbstractSection
8+
{
9+
/** @var array */
10+
protected $properties = [];
11+
12+
protected const PROPERTIES = [];
13+
14+
/**
15+
* @return array
16+
*/
17+
public function getProperties(): array
18+
{
19+
return $this->properties;
20+
}
21+
22+
/**
23+
* @param $name
24+
* @param $arguments
25+
*
26+
* @throws PropertyNotSupportedException
27+
* @return UnitSection|mixed
28+
*/
29+
public function __call($name, $arguments)
30+
{
31+
preg_match('/(?<type>get|set|should)(?<property>.*)/', $name, $match);
32+
33+
if (!in_array($match['property'], static::PROPERTIES)) {
34+
throw new PropertyNotSupportedException($match['property'], static::class);
35+
}
36+
37+
if ($match['type'] === 'set') {
38+
$this->properties[$match['property']] = $arguments[0];
39+
return $this;
40+
}
41+
42+
return $this->properties[$match['property']] ?? null;
43+
}
44+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace SystemCtl\Template\Section;
4+
5+
/**
6+
* InstallSection
7+
*
8+
* @method InstallSection setAlias(array $alias) A space-separated list of additional names for this unit
9+
* @method InstallSection setRequiredBy(array $req) Set up unit requirements for this unit
10+
* @method InstallSection setWantedBy(array $wanted) Set up unit requirements for this unit
11+
* @method InstallSection setAlso(array $also) Additional units to install/deinstall when installed/deinstalled
12+
*
13+
* @method array getAlias()
14+
* @method array getRequiredBy()
15+
* @method array getWantedBy()
16+
* @method array getAlso()
17+
*
18+
* @package SystemCtl\Template\Section
19+
* @author icanhazstring <[email protected]>
20+
*/
21+
class InstallSection extends AbstractSection
22+
{
23+
protected const PROPERTIES = [
24+
'Alias',
25+
'RequiredBy',
26+
'WantedBy',
27+
'Also'
28+
];
29+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
namespace SystemCtl\Template\Section;
4+
5+
/**
6+
* ServiceSection
7+
*
8+
* @method ServiceSection setType(string $type) Configures the unit process startup type
9+
* @method ServiceSection setEnvironment(array $env) Specify a list of environment variables
10+
* @method ServiceSection setEnvironmentFile(string $envFile) Specifiy a file with environment variables
11+
* @method ServiceSection setExecStart(string $execStart) Specifies commands or scripts to be executed when started
12+
* @method ServiceSection setExecStop(string $execStop) Specifies commands or scripts to be executed when stopped
13+
* @method ServiceSection setExecReload(string $execReload) Specifies commands or scripts to be executed when reloaded
14+
* @method ServiceSection setRestart(string $restart) Restart service of the process exists
15+
* @method ServiceSection setRemainsAfterExit(bool $rae) Consider service as active when all processes existed
16+
* @method ServiceSection setPIDFile(string $pidFile) Absolute file name pointing to the PID file of this daemon
17+
*
18+
* @method string getType()
19+
* @method array getEnvironment()
20+
* @method string getEnvironmentFile()
21+
* @method string getExecStart()
22+
* @method string getExecStop()
23+
* @method string getExecReload()
24+
* @method string getRestart()
25+
* @method bool shouldRemainsAfterExit()
26+
* @method string getPIDFile()
27+
*
28+
* @package SystemCtl\Template\Section
29+
* @author icanhazstring <[email protected]>
30+
*/
31+
class ServiceSection extends AbstractSection
32+
{
33+
protected const PROPERTIES = [
34+
'Type',
35+
'Environment',
36+
'EnvironmentFile',
37+
'ExecStart',
38+
'ExecStop',
39+
'ExecReload',
40+
'Restart',
41+
'RemainsAfterExit',
42+
'PIDFile'
43+
];
44+
45+
/**
46+
* The default value. The process started with ExecStart is the main process of the service.
47+
*/
48+
public const TYPE_SIMPLE = 'simple';
49+
/**
50+
* The process started with ExecStart spawns a child process that becomes the main process of the service.
51+
* The parent process exits when the startup is complete.
52+
*/
53+
public const TYPE_FORKING = 'forking';
54+
/**
55+
* This type is similar to simple, but the process exits before starting consequent units.
56+
*/
57+
public const TYPE_ONESHOT = 'oneshot';
58+
/**
59+
* This type is similar to simple, but consequent units are started only after the main process gains a D-Bus name.
60+
*/
61+
public const TYPE_DBUS = 'dbus';
62+
/**
63+
* This type is similar to simple, but consequent units are started only
64+
* after a notification message is sent via the sd_notify() function.
65+
*/
66+
public const TYPE_NOTIFY = 'notify';
67+
/**
68+
* Similar to simple, the actual execution of the service binary is delayed until
69+
* all jobs are finished, which avoids mixing the status output with shell output of services.
70+
*/
71+
public const TYPE_IDLE = 'idle';
72+
73+
/**
74+
* List of all possible unit types
75+
*/
76+
public const TYPES = [
77+
self::TYPE_SIMPLE,
78+
self::TYPE_FORKING,
79+
self::TYPE_ONESHOT,
80+
self::TYPE_DBUS,
81+
self::TYPE_NOTIFY,
82+
self::TYPE_IDLE
83+
];
84+
}

0 commit comments

Comments
 (0)