Skip to content

Commit 74ae404

Browse files
committed
Rework receiving and execution of units.
This is preparation for v1.0 to implement all kind of units and creation of units.
1 parent 6b79594 commit 74ae404

File tree

10 files changed

+253
-260
lines changed

10 files changed

+253
-260
lines changed

composer.lock

Lines changed: 119 additions & 118 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Exception/CommandFailedException.php

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,27 @@
22

33
namespace SystemCtl\Exception;
44

5+
/**
6+
* CommandFailedException
7+
*
8+
* @method static CommandFailedException fromService(string $unitName, string $command)
9+
* @method static CommandFailedException fromTimer(string $unitName, string $command)
10+
*
11+
* @package SystemCtl\Exception
12+
*
13+
* @author icanhazstring <[email protected]>
14+
*/
515
class CommandFailedException extends \Exception
616
{
7-
/**
8-
* @param $name
9-
* @param $command
10-
*
11-
* @return CommandFailedException
12-
*/
13-
public static function fromService($name, $command): CommandFailedException
17+
public static function __callStatic($name, $arguments)
1418
{
15-
return new self(sprintf('Failed to %s service %s', $command, $name));
16-
}
19+
preg_match('/from(?<unit>.*)/', $name, $match);
1720

18-
/**
19-
* @param $name
20-
* @param $command
21-
*
22-
* @return CommandFailedException
23-
*/
24-
public static function fromTimer($name, $command): CommandFailedException
25-
{
26-
return new self(sprintf('Failed to %s timer %s', $command, $name));
21+
$unit = strtolower($match['unit']);
22+
23+
$unitName = $arguments[0];
24+
$command = $arguments[1];
25+
26+
return new self("Failed to {$command} {$unit} {$unitName}");
2727
}
2828
}

src/Exception/UnitTypeNotSupportedException.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<?php
22

3-
43
namespace SystemCtl\Exception;
54

65
class UnitTypeNotSupportedException extends \Exception

src/SystemCtl.php

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,23 @@
44

55
use Symfony\Component\Process\ProcessBuilder;
66
use SystemCtl\Exception\UnitTypeNotSupportedException;
7+
use SystemCtl\Unit\AbstractUnit;
78
use SystemCtl\Unit\Service;
89
use SystemCtl\Unit\Timer;
910
use SystemCtl\Unit\UnitInterface;
1011

12+
/**
13+
* SystemCtl
14+
*
15+
* @method Service getService(string $unit)
16+
* @method Timer getTimer(string $unit)
17+
*
18+
* @method array getServices(?string $unitPrefix = null)
19+
* @method array getTimers(?string $unitPrefix = null)
20+
*
21+
* @package SystemCtl
22+
* @author icanhazstring <[email protected]>
23+
*/
1124
class SystemCtl
1225
{
1326
/** @var string systemctl binary path */
@@ -100,47 +113,52 @@ public function listUnits(?string $unitPrefix = null, array $unitTypes = self::S
100113
}, []);
101114
}
102115

103-
/**
104-
* @param string $name
105-
* @return Service
106-
*/
107-
public function getService(string $name): Service
116+
public function __call($name, $arguments)
108117
{
109-
return new Service($name, $this->getProcessBuilder());
110-
}
118+
preg_match('/get(?<unit>[^s]+)(?<plural>s)?/', $name, $match);
111119

112-
/**
113-
* @param null|string $unitPrefix
114-
* @return Service[]
115-
*/
116-
public function getServices(?string $unitPrefix = null): array
117-
{
118-
$units = $this->listUnits($unitPrefix, [Service::UNIT]);
120+
$isPlural = isset($match['plural']);
121+
$unitName = strtolower($match['unit']);
119122

120-
return array_map(function ($unitName) {
121-
return new Service($unitName, $this->getProcessBuilder());
122-
}, $units);
123+
if (!in_array($unitName, self::SUPPORTED_UNITS)) {
124+
throw new UnitTypeNotSupportedException("Unit {$unitName} not supported");
125+
}
126+
127+
// Singular differs requested name?
128+
// Get a list of units
129+
if ($isPlural) {
130+
return $this->getUnits(ucfirst($unitName), $arguments);
131+
}
132+
133+
return $this->getUnit(ucfirst($unitName), $arguments);
123134
}
124135

125136
/**
126-
* @param string $name
127-
* @return Timer
137+
* @param string $unitClass
138+
* @param $args
139+
* @return AbstractUnit
128140
*/
129-
public function getTimer(string $name): Timer
141+
private function getUnit(string $unitClass, $args): AbstractUnit
130142
{
131-
return new Timer($name, $this->getProcessBuilder());
143+
$args[] = $this->getProcessBuilder();
144+
$className = '\SystemCtl\Unit\\' . $unitClass;
145+
146+
return new $className(...$args);
132147
}
133148

134149
/**
135-
* @param null|string $unitPrefix
136-
* @return Timer[]
150+
* @param string $unitName
151+
* @param $arguments
152+
* @return array
137153
*/
138-
public function getTimers(?string $unitPrefix = null): array
154+
private function getUnits(string $unitName, $arguments): array
139155
{
140-
$units = $this->listUnits($unitPrefix, [Timer::UNIT]);
156+
$unitPrefix = $arguments[0] ?? null;
157+
$units = $this->listUnits($unitPrefix, [strtolower($unitName)]);
158+
$unitClass = '\SystemCtl\Unit\\' . $unitName;
141159

142-
return array_map(function ($unitName) {
143-
return new Timer($unitName, $this->getProcessBuilder());
160+
return array_map(function ($unitName) use ($unitClass) {
161+
return new $unitClass($unitName, $this->getProcessBuilder());
144162
}, $units);
145163
}
146164

src/Unit/AbstractUnit.php

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@
33
namespace SystemCtl\Unit;
44

55
use Symfony\Component\Process\ProcessBuilder;
6+
use SystemCtl\Exception\CommandFailedException;
67

78
abstract class AbstractUnit implements UnitInterface
89
{
10+
/** @var string */
11+
protected $type;
12+
913
/** @var string */
1014
private $name;
1115

@@ -53,36 +57,55 @@ public function getInstanceName(): ?string
5357
* Execute a single command
5458
*
5559
* @param string $command
60+
* @param bool $raise
61+
*
62+
* @throws CommandFailedException Raised if process was not successful and user wants to raise exception
63+
* instead of returning the actual process exit code
64+
*
5665
* @return bool
5766
*/
58-
abstract protected function execute(string $command): bool;
67+
protected function execute(string $command, bool $raise = true): bool
68+
{
69+
$process = $this->processBuilder
70+
->setArguments([$command, $this->getName()])
71+
->getProcess();
5972

60-
public function start(): bool
73+
$process->run();
74+
75+
if (!$process->isSuccessful() && $raise) {
76+
$exceptionCall = CommandFailedException::class . '::from' . ucfirst($this->type);
77+
throw call_user_func_array($exceptionCall, [$this->getName(), $command]);
78+
}
79+
80+
return $process->isSuccessful();
81+
}
82+
83+
public function start(bool $raise = true): bool
6184
{
62-
return $this->execute(__FUNCTION__);
85+
return $this->execute(__FUNCTION__, $raise);
6386
}
6487

65-
public function stop(): bool
88+
public function stop(bool $raise = true): bool
6689
{
6790
return $this->execute(__FUNCTION__);
6891
}
6992

70-
public function disable(): bool
93+
public function disable(bool $raise = true): bool
7194
{
7295
return $this->execute(__FUNCTION__);
7396
}
7497

75-
public function reload(): bool
98+
public function reload(bool $raise = true): bool
7699
{
77100
return $this->execute(__FUNCTION__);
78101
}
79102

80-
public function restart(): bool
103+
public function restart(bool $raise = true): bool
81104
{
82105
return $this->execute(__FUNCTION__);
83106
}
84107

85-
public function enable(): bool
108+
public function enable(bool $raise = true): bool
86109
{
87110
return $this->execute(__FUNCTION__);
88111
}

src/Unit/Service.php

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,15 @@
33

44
namespace SystemCtl\Unit;
55

6-
use SystemCtl\Exception\CommandFailedException;
6+
use Symfony\Component\Process\ProcessBuilder;
77

88
class Service extends AbstractUnit
99
{
1010
public const UNIT = 'service';
1111

12-
protected function execute(string $command): bool
12+
public function __construct($name, ProcessBuilder $processBuilder)
1313
{
14-
$process = $this->processBuilder
15-
->setArguments([$command, $this->getName()])
16-
->getProcess();
17-
18-
$process->run();
19-
20-
if (!$process->isSuccessful()) {
21-
throw CommandFailedException::fromService($this->getName(), $command);
22-
}
23-
24-
return true;
14+
parent::__construct($name, $processBuilder);
15+
$this->type = self::UNIT;
2516
}
2617
}

src/Unit/Timer.php

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,18 @@
22

33
namespace SystemCtl\Unit;
44

5-
use SystemCtl\Exception\CommandFailedException;
5+
use Symfony\Component\Process\ProcessBuilder;
66

77
class Timer extends AbstractUnit
88
{
99
public const UNIT = 'timer';
1010

11-
protected function execute(string $command): bool
11+
/**
12+
* @inheritdoc
13+
*/
14+
public function __construct($name, ProcessBuilder $processBuilder)
1215
{
13-
$process = $this->processBuilder
14-
->setArguments([$command, $this->getName()])
15-
->getProcess();
16-
17-
$process->run();
18-
19-
if (!$process->isSuccessful()) {
20-
throw CommandFailedException::fromTimer($this->getName(), $command);
21-
}
22-
23-
return true;
16+
parent::__construct($name, $processBuilder);
17+
$this->type = self::UNIT;
2418
}
2519
}

src/Unit/UnitInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
/**
66
* UnitInterface for handling single units
77
*
8-
* @package SystemCtl
8+
* @package SystemCtl\Unit
99
*/
1010
interface UnitInterface
1111
{

tests/SystemCtlTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,14 @@ public function testCreateUnitFromUnsupportedSuffixShouldRaiseException()
9797
SystemCtl::unitFromSuffix('unsupported', 'FailUnit');
9898
}
9999

100+
public function testGetUnitFromUnsupportedShouldRaiseException()
101+
{
102+
$systemctl = $this->buildSystemCtlMock('');
103+
104+
$this->expectException(UnitTypeNotSupportedException::class);
105+
$systemctl->getFubar('Test');
106+
}
107+
100108
public function testGetServiceWithName()
101109
{
102110
$output = 'testService.service Active Running';

0 commit comments

Comments
 (0)