diff --git a/README.textile b/README.textile index 22f5d57..593074d 100644 --- a/README.textile +++ b/README.textile @@ -1,7 +1,6 @@ h2. About -Respect\Daemon is PHP component to create and manage deamons using OS specific -tools. +Respect\Daemon is PHP component to create and manage deamons using OS specific tools. h3. Sample Usage (not working yet) @@ -27,5 +26,4 @@ Manages upstart (http://upstart.ubuntu.com) scripts and cron jobs. h3. Windows -Manager windows services using the Windows Service Management API (through the -win32service PECL extension). \ No newline at end of file +Manager windows services using the Windows Service Management API (through the win32service PECL extension). \ No newline at end of file diff --git a/library/Respect/Daemon/Adapters/Upstart.php b/library/Respect/Daemon/Adapters/Upstart.php index 0a51e50..4e241cf 100644 --- a/library/Respect/Daemon/Adapters/Upstart.php +++ b/library/Respect/Daemon/Adapters/Upstart.php @@ -4,6 +4,12 @@ use Respect\Daemon\Exceptions\DirectoryNotFoundException; use \UnexpectedValueException; +use \DirectoryIterator; +use Respect\Daemon\Job; +use Respect\Daemon\Meta; +use Respect\Daemon\Trigger; +use Respect\Daemon\EventListener; +use Respect\Daemon\Executable; class Upstart { @@ -11,18 +17,18 @@ class Upstart protected $dir; protected $dirHandle; - public static function runsOnCurrentEnvironment() + public static function runsOnEnvironment() { $uname = php_uname(); if (!stripos($uname, 'linux')) return false; - return stripos(system('initctl --vesion'), 'upstart'); + return false !== stripos(system('initctl --vesion'), 'upstart'); } - public function __construct() + public function __construct($dir='/etc/init') { try { - $this->dir = trim(realpath('/etc/init'), DIRECTORY_SEPARATOR); + $this->dir = rtrim(realpath($dir), DIRECTORY_SEPARATOR); $this->dirHandle = new DirectoryIterator($this->dir); } catch (UnexpectedValueException $e) { throw new DirectoryNotFoundException( @@ -37,7 +43,7 @@ public function all() foreach ($this->dirHandle as $jobFile) { if (!$jobFile->isFile()) continue; - $scripts[] = $jobFile->getFilename(); + $scripts[] = $jobFile->getBasename('.conf'); } return $scripts; } @@ -58,8 +64,9 @@ public function remove($jobName) public function get($jobName) { return $this->getJobFromDefinition( + $jobName, file_get_contents( - $this->dir . DIRECTORY_SEPARATOR . $job->getName() + $this->dir . DIRECTORY_SEPARATOR . $jobName . '.conf' ) ); } @@ -84,9 +91,138 @@ protected function getDefinition(Job $job) } - protected function getJobFromDefinition($definition) + public function getJobFromDefinition($name, $definition) { - + $lines = explode(PHP_EOL, $definition); + $job = new Job($name); + $previousStanza = null; + $scriptData = array(); + foreach ($lines as $l) { + $stanza = $this->findStanza($l); + if ( + (stripos($previousStanza, 'script') !== false + && $previousStanza !== 'end script' + ) || !empty($scriptData)) { + $scriptData[] = $l; + } + switch ($stanza) { + //meta + case 'author': + case 'console': + case 'description': + case 'emits': + case 'env': + case 'expect': + case 'export': + case 'instance': + case 'kill': + case 'normal exit': + case 'oom': + case 'respawn': + case 'task': + case 'umask': + $job->addMeta( + new Meta( + $stanza, + $this->findSingleValue($stanza, $l) + ) + ); + break; + //script + case 'script': + case 'post-start script': + case 'post-stop script': + case 'pre-start script': + case 'pre-stop script': + $scriptData[] = trim(str_replace('script', '', $stanza)) ? : 'main'; + break; + case 'end script': + $job->addTrigger( + new Trigger( + array_shift($scriptData), + new Script(implode(PHP_EOL, $scriptData)) + ) + ); + $scriptData = array(); + break; + //events + case 'exec': + case 'post-start exec': + case 'post-stop exec': + case 'pre-start exec': + case 'pre-stop exec': + $job->addTrigger( + new Trigger( + trim(str_replace('exec', '', $stanza)) ? : 'main', + new Executable($this->findSingleValue($stanza, $l)) + ) + ); + break; + case 'start on': + case 'stop on': + $job->addEventListener( + new EventListener( + trim(str_replace('on', '', $stanza)), + $this->findSingleValue($stanza, $l) + ) + ); + break; + //not implemented + default: + break; + } + $previousStanza = $stanza; + } + return $job; + } + + protected function findSingleValue($stanza, $line) + { + if ($this->findStanza($line) !== $stanza) + return; + return trim(str_replace($stanza, '', $line), " \n\t\r\0\x0B\""); + } + + protected function findStanza($line) + { + $stanzas = array( + 'author', + 'chdir', + 'chroot', + 'console', + 'description', + 'emits', + 'env', + 'exec', + 'expect', + 'export', + 'instance', + 'kill', + 'limit', + 'nice', + 'normal exit', + 'oom', + 'post-start exec', + 'post-stop exec', + 'pre-start exec', + 'pre-stop exec', + 'post-start script', + 'post-stop script', + 'pre-start script', + 'pre-stop script', + 'respawn', + 'script', + 'session leader', + 'start on', + 'stop on', + 'task', + 'umask', + 'version' + ); + $line = trim($line); + foreach ($stanzas as $s) + if (stripos($line, $s) === 0) + return $s; } } \ No newline at end of file diff --git a/library/Respect/Daemon/EventListener.php b/library/Respect/Daemon/EventListener.php index 1ee9adc..13317cd 100644 --- a/library/Respect/Daemon/EventListener.php +++ b/library/Respect/Daemon/EventListener.php @@ -2,36 +2,30 @@ namespace Respect\Daemon; -class EventListener +class EventListener extends Meta { - protected $action; - protected $event; + protected $name; + protected $value; - public function __construct($action='', $event='') + public function getName() { - $this->action = $action; - $this->event = $event; + return $this->name; } - public function getAction() + public function setName($name) { - return $this->action; + $this->name = $name; } - public function setAction($action) + public function getValue() { - $this->action = $action; + return $this->value; } - public function getEvent() + public function setValue($value) { - return $this->event; - } - - public function setEvent($event) - { - $this->event = $event; + $this->value = $value; } } \ No newline at end of file diff --git a/library/Respect/Daemon/Exceptions/DirectoryNotFoundException.php b/library/Respect/Daemon/Exceptions/DirectoryNotFoundException.php index bed1e3f..48b371d 100644 --- a/library/Respect/Daemon/Exceptions/DirectoryNotFoundException.php +++ b/library/Respect/Daemon/Exceptions/DirectoryNotFoundException.php @@ -2,6 +2,8 @@ namespace Respect\Daemon\Exceptions; +use \Exception; + class DirectoryNotFoundException extends Exception { diff --git a/library/Respect/Daemon/Executable.php b/library/Respect/Daemon/Executable.php index b4c32c7..51e9ed8 100644 --- a/library/Respect/Daemon/Executable.php +++ b/library/Respect/Daemon/Executable.php @@ -2,9 +2,14 @@ namespace Respect\Daemon; -class Executable +class Executable implements Runnable { protected $path; + public function __construct($path) + { + $this->path = $path; + } + } \ No newline at end of file diff --git a/library/Respect/Daemon/Job.php b/library/Respect/Daemon/Job.php index 0a8ee8e..4f262e2 100644 --- a/library/Respect/Daemon/Job.php +++ b/library/Respect/Daemon/Job.php @@ -5,71 +5,33 @@ class Job { - protected $name; - protected $description; - protected $main; - protected $preStart; - protected $postStop; + protected $meta = array(); protected $eventListeners = array(); + protected $triggers = array(); public function __construct($name) { - + $this->name = $name; } - public function getName() + public function addTrigger(Trigger $trigger) { - return $this->name; + $this->triggers[spl_object_hash($trigger)] = $trigger; } - public function getDescription() + public function removeTrigger(Trigger $trigger) { - return $this->description; + unset($this->triggers[spl_object_hash($trigger)]); } - public function getMain() + public function addMeta(Meta $meta) { - return $this->main; + $this->meta[spl_object_hash($meta)] = $meta; } - public function getPreStart() - { - return $this->preStart; - } - - public function getPostStop() - { - return $this->postStop; - } - - public function setDescription($description) - { - $this->description = $description; - } - - public function setMain(Runnable $main) - { - $this->main = $main; - } - - public function setPreStart(Script $preStart) - { - $this->preStart = $preStart; - } - - public function setPostStop(Script $postStop) - { - $this->postStop = $postStop; - } - - public function addEventListener(Event $event) + public function addEventListener(EventListener $event) { $this->eventListeners[spl_object_hash($event)] = $event; } - public function removeEventListener(Event $event) - { - unset($this->eventListeners[spl_object_hash($event)]); - } - } \ No newline at end of file diff --git a/library/Respect/Daemon/Manager.php b/library/Respect/Daemon/Manager.php index 3e5e5e7..260f897 100644 --- a/library/Respect/Daemon/Manager.php +++ b/library/Respect/Daemon/Manager.php @@ -30,7 +30,7 @@ public static function getAvailableAdapters() $runs = call_user_func( array( '\Respect\Daemon\Adapters\\' . $adapterName, - 'runsOnCurrentEnvironment' + 'runsOnEnvironment' ) ); if ($runs) diff --git a/library/Respect/Daemon/Meta.php b/library/Respect/Daemon/Meta.php new file mode 100644 index 0000000..166e183 --- /dev/null +++ b/library/Respect/Daemon/Meta.php @@ -0,0 +1,36 @@ +name = $name; + $this->value = $value; + } + + public function getName() + { + return $this->name; + } + + public function setName($name) + { + $this->name = $name; + } + + public function getValue() + { + return $this->value; + } + + public function setValue($value) + { + $this->value = $value; + } + +} \ No newline at end of file diff --git a/library/Respect/Daemon/Runnable.php b/library/Respect/Daemon/Runnable.php index c54194d..869931a 100644 --- a/library/Respect/Daemon/Runnable.php +++ b/library/Respect/Daemon/Runnable.php @@ -4,6 +4,5 @@ interface Runnable { - - public function run(); + } \ No newline at end of file diff --git a/library/Respect/Daemon/Script.php b/library/Respect/Daemon/Script.php index 2a5736a..bc60dfe 100644 --- a/library/Respect/Daemon/Script.php +++ b/library/Respect/Daemon/Script.php @@ -7,4 +7,9 @@ class Script protected $body; + public function __construct($body) + { + $this->body = $body; + } + } \ No newline at end of file diff --git a/library/Respect/Daemon/Trigger.php b/library/Respect/Daemon/Trigger.php new file mode 100644 index 0000000..79df320 --- /dev/null +++ b/library/Respect/Daemon/Trigger.php @@ -0,0 +1,37 @@ +action = $action; + $this->event = $event; + } + + public function getAction() + { + return $this->action; + } + + public function setAction(Runnable $action) + { + $this->action = $action; + } + + public function getEvent() + { + return $this->event; + } + + public function setEvent($event) + { + $this->event = $event; + } + +} \ No newline at end of file diff --git a/library/SplClassLoader.php b/library/SplClassLoader.php new file mode 100644 index 0000000..9208dca --- /dev/null +++ b/library/SplClassLoader.php @@ -0,0 +1,141 @@ +register(); + * + * @author Jonathan H. Wage + * @author Roman S. Borschel + * @author Matthew Weier O'Phinney + * @author Kris Wallsmith + * @author Fabien Potencier + */ +class SplClassLoader +{ + + private $_fileExtension = '.php'; + private $_namespace; + private $_includePath; + private $_namespaceSeparator = '\\'; + + /** + * Creates a new SplClassLoader that loads classes of the + * specified namespace. + * + * @param string $ns The namespace to use. + */ + public function __construct($ns = null, $includePath = null) + { + $this->_namespace = $ns; + $this->_includePath = $includePath; + } + + /** + * Sets the namespace separator used by classes in the namespace of this class loader. + * + * @param string $sep The separator to use. + */ + public function setNamespaceSeparator($sep) + { + $this->_namespaceSeparator = $sep; + } + + /** + * Gets the namespace seperator used by classes in the namespace of this class loader. + * + * @return void + */ + public function getNamespaceSeparator() + { + return $this->_namespaceSeparator; + } + + /** + * Sets the base include path for all class files in the namespace of this class loader. + * + * @param string $includePath + */ + public function setIncludePath($includePath) + { + $this->_includePath = $includePath; + } + + /** + * Gets the base include path for all class files in the namespace of this class loader. + * + * @return string $includePath + */ + public function getIncludePath() + { + return $this->_includePath; + } + + /** + * Sets the file extension of class files in the namespace of this class loader. + * + * @param string $fileExtension + */ + public function setFileExtension($fileExtension) + { + $this->_fileExtension = $fileExtension; + } + + /** + * Gets the file extension of class files in the namespace of this class loader. + * + * @return string $fileExtension + */ + public function getFileExtension() + { + return $this->_fileExtension; + } + + /** + * Installs this class loader on the SPL autoload stack. + */ + public function register() + { + spl_autoload_register(array($this, 'loadClass')); + } + + /** + * Uninstalls this class loader from the SPL autoloader stack. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $className The name of the class to load. + * @return void + */ + public function loadClass($className) + { + if (null === $this->_namespace || $this->_namespace . $this->_namespaceSeparator === substr($className, + 0, strlen($this->_namespace . $this->_namespaceSeparator))) { + $fileName = ''; + $namespace = ''; + if (false !== ($lastNsPos = strripos($className, + $this->_namespaceSeparator))) { + $namespace = substr($className, 0, $lastNsPos); + $className = substr($className, $lastNsPos + 1); + $fileName = str_replace($this->_namespaceSeparator, + DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR; + } + $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . $this->_fileExtension; + + require ($this->_includePath !== null ? $this->_includePath . DIRECTORY_SEPARATOR : '') . $fileName; + } + } + +} \ No newline at end of file diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 0000000..1a9e6a1 --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,7 @@ +register(); \ No newline at end of file diff --git a/tests/library/Respect/Daemon/Adapter/UpstartTest.php b/tests/library/Respect/Daemon/Adapter/UpstartTest.php new file mode 100644 index 0000000..13c5845 --- /dev/null +++ b/tests/library/Respect/Daemon/Adapter/UpstartTest.php @@ -0,0 +1,41 @@ +object = new Upstart(); + } + + public function testFoo() + { + $job = $this->object->getJobFromDefinition("acpid", + '# acpid - ACPI daemon +# +# The ACPI daemon provides a socket for other daemons to multiplex kernel +# ACPI events from, and a framework for reacting to those events. + +description "ACPI daemon" + +start on runlevel [2345] +stop on runlevel [!2345] + +expect fork +respawn + +exec acpid -c /etc/acpi/events -s /var/run/acpid.socket'); + } + + public function testBar() + { + $all = $this->object->all(); + foreach ($all as &$a) $a = $this->object->get($a); + print_r($all); + } + +} \ No newline at end of file diff --git a/tests/phpunit.xml b/tests/phpunit.xml new file mode 100644 index 0000000..5f909a6 --- /dev/null +++ b/tests/phpunit.xml @@ -0,0 +1,12 @@ + +