hotfix: Added aliases, implemented new runners
This commit is contained in:
		@@ -7,7 +7,26 @@ require_once __DIR__."/systemtest.php";
 | 
			
		||||
if (file_exists(__DIR__."/banner.php"))
 | 
			
		||||
    require_once __DIR__."/banner.php";
 | 
			
		||||
 | 
			
		||||
use NoccyLabs\Hotfix\Hotfix\AliasManager;
 | 
			
		||||
use NoccyLabs\Hotfix\Service\ServiceManager;
 | 
			
		||||
use NoccyLabs\Hotfix\Service;
 | 
			
		||||
use NoccyLabs\Hotfix\HotfixApplication;
 | 
			
		||||
 | 
			
		||||
// Register services
 | 
			
		||||
ServiceManager::registerService(new Service\IxService());
 | 
			
		||||
 | 
			
		||||
// Register aliases
 | 
			
		||||
$paths = [
 | 
			
		||||
    getenv("HOME")."/.hotfix.conf",
 | 
			
		||||
    "/etc/hotfix.conf"
 | 
			
		||||
];
 | 
			
		||||
foreach ($paths as $path) {
 | 
			
		||||
    if (file_exists($path)) {
 | 
			
		||||
        AliasManager::registerFromConfig($path);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Start the application
 | 
			
		||||
$app = new HotfixApplication();
 | 
			
		||||
$app->run();
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								examples/bash-facts.fix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								examples/bash-facts.fix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
hotfix: This hotfix show how to use facts in bash
 | 
			
		||||
info:   >
 | 
			
		||||
        This lets you retrieve some additional system information during
 | 
			
		||||
        runtime. Use 'hotfix facts' to see all the known facts.
 | 
			
		||||
author: Noccy <cvagnetoft@gmail.com>
 | 
			
		||||
lang:   bash
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
info "Architecture: $(fact system.arch)"
 | 
			
		||||
info "Distribution: $(fact lsb.id)"
 | 
			
		||||
							
								
								
									
										4
									
								
								hotfix.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								hotfix.conf
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
[alias]
 | 
			
		||||
gist=https://gist.githubusercontent.com/{fix}/raw
 | 
			
		||||
pastebin=https:/pastebin.com/raw/{fix}
 | 
			
		||||
noccy=http://files.noccy.com/hotfix/{fix}.fix.signed
 | 
			
		||||
							
								
								
									
										5
									
								
								installer/make-installer.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										5
									
								
								installer/make-installer.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
cp ../hotfix src/hotfix
 | 
			
		||||
cp ../hotfix.conf src/hotfix.conf
 | 
			
		||||
cp ../LICENSE src/LICENSE
 | 
			
		||||
makeself --copy src hotfix-installer.run hotfix ./install.sh
 | 
			
		||||
@@ -66,6 +66,13 @@ function do_install {
 | 
			
		||||
    fi
 | 
			
		||||
    chmod +x $1/hotfix
 | 
			
		||||
 | 
			
		||||
    if [ -f $HOME/.hotfix.conf ]; then
 | 
			
		||||
        debug "~/.hotfix.conf already exists, will not overwrite"
 | 
			
		||||
    else
 | 
			
		||||
        debug "Copying hotfix.conf into ~/.hotfix.conf"
 | 
			
		||||
        cp hotfix.conf $HOME/.hotfix.conf
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    debug "Verifying that hotfix is callable..."
 | 
			
		||||
    source ~/.profile &>/dev/null
 | 
			
		||||
    source ~/.bashrc &>/dev/null
 | 
			
		||||
 
 | 
			
		||||
@@ -12,8 +12,10 @@ use Symfony\Component\Console\Question\ConfirmationQuestion;
 | 
			
		||||
use Symfony\Component\Console\Question\ChoiceQuestion;
 | 
			
		||||
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
 | 
			
		||||
use NoccyLabs\Hotfix\Hotfix\Loader;
 | 
			
		||||
use NoccyLabs\Hotfix\Hotfix\Hotfix;
 | 
			
		||||
use NoccyLabs\Hotfix\System\Facts;
 | 
			
		||||
 | 
			
		||||
use NoccyLabs\Hotfix\Runner\RunnerFactory;
 | 
			
		||||
use NoccyLabs\Hotfix\Hotfix\HotfixLoader;
 | 
			
		||||
 | 
			
		||||
class ApplyCommand extends Command
 | 
			
		||||
{
 | 
			
		||||
@@ -26,7 +28,7 @@ class ApplyCommand extends Command
 | 
			
		||||
        $this->addOption("insecure", "I", InputOption::VALUE_NONE, "Disable signature checks. Don't use unless you know what you are doing!");
 | 
			
		||||
        $this->addOption("preview", "p", InputOption::VALUE_NONE, "Only preview the hotfix script, don't apply anything");
 | 
			
		||||
 | 
			
		||||
        $this->addArgument("hotfix", InputArgument::OPTIONAL, "The identifier, path or filename of the hotfix");
 | 
			
		||||
        $this->addArgument("hotfix", InputArgument::OPTIONAL, "The identifier or filename of the hotfix");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function execute(InputInterface $input, OutputInterface $output)
 | 
			
		||||
@@ -34,69 +36,45 @@ class ApplyCommand extends Command
 | 
			
		||||
        $this->output = $output;
 | 
			
		||||
 | 
			
		||||
        $fix = $input->getArgument("hotfix");
 | 
			
		||||
        $insecure = $input->getOption("insecure");
 | 
			
		||||
        $loader = new Loader();
 | 
			
		||||
 | 
			
		||||
        if (!$fix) {
 | 
			
		||||
        
 | 
			
		||||
            $loaders = $loader->getLoaders();
 | 
			
		||||
            $output->writeln("Supported loaders:\n");
 | 
			
		||||
            foreach ($loaders as $loader) {
 | 
			
		||||
                $output->writeln(" * ".$loader->getInfo());
 | 
			
		||||
            }
 | 
			
		||||
            $output->writeln("No hotfix specified.");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //$loader = new Loader();
 | 
			
		||||
        $output->writeln("Reading hotfix <comment>{$fix}</comment>...");
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            $hotfix = $loader->load($fix, $insecure);
 | 
			
		||||
            $hotfix = HotfixLoader::load($fix);
 | 
			
		||||
            //$hotfix = $loader->load($fix, $insecure);
 | 
			
		||||
        } catch (\Exception $e) {
 | 
			
		||||
            $output->writeln("<error>Error: ".$e->getMessage()."</error>");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if (!$hotfix) {
 | 
			
		||||
            $output->writeln("<error>Could not load hotfix</error>");
 | 
			
		||||
 | 
			
		||||
        $output->writeln("");
 | 
			
		||||
 | 
			
		||||
        $header = $hotfix->getHeader();
 | 
			
		||||
        $output->writeln("  Hotfix:  <fg=yellow;options=bold>".$header->getName()."</fg=yellow;options=bold>");
 | 
			
		||||
        $output->writeln("  Author:  <comment>".$header->getAuthor()."</comment>");
 | 
			
		||||
        $info = explode("\n",wordwrap(trim($header->getInfo()), 60));
 | 
			
		||||
        $info = "<comment>".join("</comment>\n           <comment>", $info)."</comment>";
 | 
			
		||||
        $output->writeln("  Info:    ".$info);
 | 
			
		||||
        $output->writeln("");
 | 
			
		||||
 | 
			
		||||
        if (!$this->checkSignature($hotfix, $output)) {
 | 
			
		||||
            if (!$input->getOption('insecure')) {
 | 
			
		||||
                $output->writeln("<error>Hotfix can not be authenticated. Aborting!</error>");
 | 
			
		||||
                return;
 | 
			
		||||
            } 
 | 
			
		||||
        }        
 | 
			
		||||
        if (!$this->checkRequirements($hotfix, $output)) {
 | 
			
		||||
            $output->writeln("<error>Error: This hotfix it not compatible with the current distribution</>");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $output->writeln("");
 | 
			
		||||
        if (($signer = $hotfix->getSignedBy())) {
 | 
			
		||||
            $keyid = $hotfix->getKeyId();
 | 
			
		||||
            $output->writeln("Hotfix has good signature from <fg=green;options=bold>{$signer}</fg=green;options=bold> (keyid <info>{$keyid}</info>)");
 | 
			
		||||
        } else {
 | 
			
		||||
            $output->writeln("<fg=red;options=bold>Warning: Hotfix is not signed or signature not valid!</fg=red;options=bold>");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        $requires = $hotfix->getRequirements();
 | 
			
		||||
        if (count($requires)>0) {
 | 
			
		||||
            $engine = new ExpressionLanguage();
 | 
			
		||||
            $facts = Facts::getSystemFacts()->getFacts();
 | 
			
		||||
            while (true) {
 | 
			
		||||
                $expr = array_shift($requires);
 | 
			
		||||
                $ret = $engine->evaluate($expr, $facts);
 | 
			
		||||
                if ($ret) {
 | 
			
		||||
                    //$output->writeln("<fg=green;options=bold>Hotfix is compatible with the current distribution</>");
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                if (count($requires)==0) {
 | 
			
		||||
                    $output->writeln("<error>Error: This hotfix it not compatible with the current distribution</>");
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        //} else {
 | 
			
		||||
            //$output->writeln("<fg=green;options=bold>Hotfix indicates universal compatibility.</>");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        $output->writeln("");
 | 
			
		||||
        $output->writeln("  Hotfix:  <fg=yellow;options=bold>".$hotfix->getName()."</fg=yellow;options=bold>");
 | 
			
		||||
        $output->writeln("  Author:  <comment>".$hotfix->getAuthor()."</comment>");
 | 
			
		||||
        $info = explode("\n",wordwrap(trim($hotfix->getInfo()), 60));
 | 
			
		||||
        $info = "<comment>".join("</comment>\n           <comment>", $info)."</comment>";
 | 
			
		||||
        $output->writeln("  Info:    ".$info);
 | 
			
		||||
        $output->writeln("");
 | 
			
		||||
        
 | 
			
		||||
        if ($input->getOption("preview")) {
 | 
			
		||||
            $output->writeln("This is the script that will be executed:");
 | 
			
		||||
            $body = $hotfix->getBody();
 | 
			
		||||
@@ -111,6 +89,7 @@ class ApplyCommand extends Command
 | 
			
		||||
        if (!$helper->ask($input, $output, $question)) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        $output->writeln("\n<info>Applying hotfix...</info>\n");
 | 
			
		||||
        try {
 | 
			
		||||
@@ -121,4 +100,39 @@ class ApplyCommand extends Command
 | 
			
		||||
        $output->writeln("\n<info>Hotfix applied successfully</info>");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function checkSignature(Hotfix $hotfix, OutputInterface $output)
 | 
			
		||||
    {
 | 
			
		||||
        $signature = $hotfix->getSignature();
 | 
			
		||||
        if ($signature->isValid()) {
 | 
			
		||||
            $keyid = $signature->getKeyId();
 | 
			
		||||
            $signer = $signature->getSigner();
 | 
			
		||||
            $output->writeln("Hotfix has good signature from <fg=green;options=bold>{$signer}</fg=green;options=bold> (keyid <info>{$keyid}</info>)");
 | 
			
		||||
        } else {
 | 
			
		||||
            $error = $signature->getError();
 | 
			
		||||
            $output->writeln("<fg=red;options=bold>Warning: {$error}</fg=red;options=bold>");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function checkRequirements(Hotfix $hotfix, OutputInterface $output)
 | 
			
		||||
    {
 | 
			
		||||
        $requires = $hotfix->getHeader()->getRequirements();
 | 
			
		||||
        if (count($requires)>0) {
 | 
			
		||||
            $engine = new ExpressionLanguage();
 | 
			
		||||
            $facts = Facts::getSystemFacts()->getFacts();
 | 
			
		||||
            while (true) {
 | 
			
		||||
                $expr = array_shift($requires);
 | 
			
		||||
                $ret = $engine->evaluate($expr, $facts);
 | 
			
		||||
                if ($ret) {
 | 
			
		||||
                    //$output->writeln("<fg=green;options=bold>Hotfix is compatible with the current distribution</>");
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                if (count($requires)==0) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -26,8 +26,10 @@ class FactsCommand extends Command
 | 
			
		||||
    protected function execute(InputInterface $input, OutputInterface $output)
 | 
			
		||||
    {
 | 
			
		||||
        $facts = Facts::getSystemFacts()->getFlat();
 | 
			
		||||
    
 | 
			
		||||
        print_r($facts);
 | 
			
		||||
 | 
			
		||||
        foreach ($facts as $fact=>$value) {
 | 
			
		||||
            $output->writeln("  <comment>{$fact}</>: <info>{$value}</>");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								src/Exception/ConfigurationException.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/Exception/ConfigurationException.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace NoccyLabs\Hotfix\Exception;
 | 
			
		||||
 | 
			
		||||
class ConfigurationException extends HotfixException
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										41
									
								
								src/Hotfix/AliasManager.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/Hotfix/AliasManager.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace NoccyLabs\Hotfix\Hotfix;
 | 
			
		||||
 | 
			
		||||
use NoccyLabs\Hotfix\Exception\ConfigurationException;
 | 
			
		||||
 | 
			
		||||
class AliasManager
 | 
			
		||||
{
 | 
			
		||||
    private static $aliases = [];
 | 
			
		||||
 | 
			
		||||
    public static function registerFromConfig($file)
 | 
			
		||||
    {
 | 
			
		||||
        $config = parse_ini_file($file, true);
 | 
			
		||||
        if (!array_key_exists('alias', $config)) {
 | 
			
		||||
            return ;
 | 
			
		||||
        }
 | 
			
		||||
        foreach ($config['alias'] as $prefix=>$url) {
 | 
			
		||||
            self::registerAlias($prefix, $url);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function registerAlias($prefix, $url)
 | 
			
		||||
    {
 | 
			
		||||
        if (strpos($url,'{fix}')===false) {
 | 
			
		||||
            throw new ConfigurationException("The alias URL for {$prefix} does not contain the magic '{fix}' placeholder");
 | 
			
		||||
        }
 | 
			
		||||
        self::$aliases[$prefix] = $url;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function getRegisteredAlises()
 | 
			
		||||
    {
 | 
			
		||||
        return self::$aliases;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function getAlias($prefix)
 | 
			
		||||
    {
 | 
			
		||||
        if (!array_key_exists($prefix,self::$aliases)) return null;
 | 
			
		||||
        return self::$aliases[$prefix];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										83
									
								
								src/Hotfix/Header.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/Hotfix/Header.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace NoccyLabs\Hotfix\Hotfix;
 | 
			
		||||
 | 
			
		||||
use Symfony\Component\Yaml\Yaml;
 | 
			
		||||
use NoccyLabs\Hotfix\Exception\HotfixException;
 | 
			
		||||
 | 
			
		||||
class Header
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @var string The name of the hotfix
 | 
			
		||||
     */
 | 
			
		||||
    protected $name;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var string Information about this hotfix
 | 
			
		||||
     */
 | 
			
		||||
    protected $info;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var string The author of the hotfix 
 | 
			
		||||
     */
 | 
			
		||||
    protected $author;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var string The language this hotfix is written in, should match a runner.
 | 
			
		||||
     */ 
 | 
			
		||||
    protected $language;
 | 
			
		||||
 | 
			
		||||
    /** 
 | 
			
		||||
     * @var array A list of expressions to verify that the system is compatible
 | 
			
		||||
     *            with this fix 
 | 
			
		||||
     */
 | 
			
		||||
    protected $requirements;
 | 
			
		||||
 | 
			
		||||
    public function __construct($header)
 | 
			
		||||
    {
 | 
			
		||||
        $header = Yaml::parse($header);
 | 
			
		||||
 | 
			
		||||
        if (!(
 | 
			
		||||
            array_key_exists('hotfix', $header) &&
 | 
			
		||||
            array_key_exists('author', $header) &&
 | 
			
		||||
            array_key_exists('info', $header) &&
 | 
			
		||||
            array_key_exists('lang', $header)
 | 
			
		||||
        )) {
 | 
			
		||||
            throw new HotfixException("Invalid hotfix, header is missing hotfix, author, info or lang fields.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->name = $header['hotfix'];
 | 
			
		||||
        $this->author = $header['author'];
 | 
			
		||||
        $this->info = $header['info'];
 | 
			
		||||
        $this->language = $header['lang'];
 | 
			
		||||
 | 
			
		||||
        if (array_key_exists('for', $header)) {
 | 
			
		||||
            $this->requirements = $header['for'];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getName()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->name;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getAuthor()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->author;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getInfo()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->info;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getLanguage()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->language;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getRequirements()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->requirements;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -3,23 +3,45 @@
 | 
			
		||||
namespace NoccyLabs\Hotfix\Hotfix;
 | 
			
		||||
 | 
			
		||||
use Symfony\Component\Yaml\Yaml;
 | 
			
		||||
use NoccyLabs\Hotfix\Runner\RunnerFactory;
 | 
			
		||||
 | 
			
		||||
class Hotfix
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    protected $signer;
 | 
			
		||||
 | 
			
		||||
    protected $keyId;
 | 
			
		||||
 | 
			
		||||
    protected $header;
 | 
			
		||||
    
 | 
			
		||||
    protected $body;
 | 
			
		||||
 | 
			
		||||
    public function __construct($hotfix, $signer)
 | 
			
		||||
    protected $signature;
 | 
			
		||||
 | 
			
		||||
    protected $origin;
 | 
			
		||||
 | 
			
		||||
    public function __construct($body, Header $header, Signature $signature, $origin)
 | 
			
		||||
    {
 | 
			
		||||
        $this->load($hotfix);
 | 
			
		||||
        $this->signer = $signer[0];
 | 
			
		||||
        $this->keyId = $signer[1];
 | 
			
		||||
        $this->header = $header;
 | 
			
		||||
        $this->body = $body;
 | 
			
		||||
        $this->signature = $signature;
 | 
			
		||||
        $this->origin = $origin;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getHeader()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->header;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getHash()
 | 
			
		||||
    {
 | 
			
		||||
        return sha1($this->body);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getSignature()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->signature;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getBody()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->body;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function load($hotfix)
 | 
			
		||||
@@ -34,88 +56,11 @@ class Hotfix
 | 
			
		||||
        $this->body = $body;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getBody()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->body;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function apply()
 | 
			
		||||
    {
 | 
			
		||||
        if (!array_key_exists('lang', $this->header)) {
 | 
			
		||||
            $lang = 'bash';
 | 
			
		||||
        } else {
 | 
			
		||||
            $lang = strtolower($this->header['lang']);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        $script = null;
 | 
			
		||||
        $head = null;
 | 
			
		||||
        $foot = null;
 | 
			
		||||
        switch ($lang) {
 | 
			
		||||
            case 'bash':
 | 
			
		||||
                $exec = "/bin/bash";
 | 
			
		||||
                $head = file_get_contents(__DIR__."/../stubs/bash.stub");
 | 
			
		||||
                break;
 | 
			
		||||
            case 'php':
 | 
			
		||||
                $exec = "/usr/bin/env php";
 | 
			
		||||
                $head = "<?php require_once \"".__DIR__."/../../vendor/autoload.php\"; ".file_get_contents(__DIR__."/../stubs/php.stub");
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
                fprintf(STDERR, "Error: Unsupported language %s\n", $lang);
 | 
			
		||||
                return;
 | 
			
		||||
        }
 | 
			
		||||
        $tmpfile = sys_get_temp_dir()."/hotfix_".sha1($this->header['hotfix']);
 | 
			
		||||
 | 
			
		||||
        file_put_contents($tmpfile, $head."\n".$this->body."\n".$foot);
 | 
			
		||||
        passthru($exec." ".$tmpfile);
 | 
			
		||||
        unlink($tmpfile);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getRequirements()
 | 
			
		||||
    {
 | 
			
		||||
        if (!array_key_exists('for',$this->header)) {
 | 
			
		||||
            return [];
 | 
			
		||||
        }
 | 
			
		||||
        return $this->header['for'];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getSignedBy()
 | 
			
		||||
    {
 | 
			
		||||
        if (!$this->signer) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return sprintf("%s <%s>", 
 | 
			
		||||
            $this->signer['uids'][0]['name'],
 | 
			
		||||
            $this->signer['uids'][0]['email']
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public function getKeyId()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->keyId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getName()
 | 
			
		||||
    {
 | 
			
		||||
        if (!array_key_exists('hotfix', $this->header)) {
 | 
			
		||||
            return "Untitled hotfix";
 | 
			
		||||
        }
 | 
			
		||||
        return $this->header['hotfix'];
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public function getInfo()
 | 
			
		||||
    {
 | 
			
		||||
        if (!array_key_exists('info', $this->header)) {
 | 
			
		||||
            return "No additional information";
 | 
			
		||||
        }
 | 
			
		||||
        return $this->header['info'];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getAuthor()
 | 
			
		||||
    {
 | 
			
		||||
        if (!array_key_exists('author', $this->header)) {
 | 
			
		||||
            return "Unknown author";
 | 
			
		||||
        }
 | 
			
		||||
        return $this->header['author'];
 | 
			
		||||
        $runner = RunnerFactory::createRunner($this);
 | 
			
		||||
        $runner->apply();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										75
									
								
								src/Hotfix/HotfixLoader.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								src/Hotfix/HotfixLoader.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,75 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace NoccyLabs\Hotfix\Hotfix;
 | 
			
		||||
 | 
			
		||||
use NoccyLabs\Hotfix\Exception\HotfixException;
 | 
			
		||||
use NoccyLabs\Hotfix\Service\ServiceManager;
 | 
			
		||||
use NoccyLabs\Hotfix\Hotfix\AliasManager;
 | 
			
		||||
 | 
			
		||||
class HotfixLoader
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    const PGP_HEADER_TOKEN = '-----BEGIN PGP SIGNATURE-----';
 | 
			
		||||
 | 
			
		||||
    public static function load($uri)
 | 
			
		||||
    {
 | 
			
		||||
        // First, check if this is a valid URL or filename
 | 
			
		||||
        if ((strpos($uri,"://")!==false) || (file_exists($uri))) {
 | 
			
		||||
            return self::loadFromUri($uri);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (strpos($uri,":")!==false) {
 | 
			
		||||
            list($prefix,$id) = explode(":",$uri,2);
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new HotfixException("Invalid hotfix specified {$uri}");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check services first, as aliases should for security reasons not
 | 
			
		||||
        // be allowed to overload services.
 | 
			
		||||
        if (($service = ServiceManager::getService($prefix))) {
 | 
			
		||||
            return self::loadFromService($service,$id);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check aliases
 | 
			
		||||
        if (($alias = AliasManager::getAlias($prefix))) {
 | 
			
		||||
            $url = str_replace('{fix}', $id, $alias);
 | 
			
		||||
            return self::loadFromUri($url);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        throw new HotfixException("Could not read hotfix {$uri}");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static function loadFromUri($url)
 | 
			
		||||
    {
 | 
			
		||||
        $source = file_get_contents($url);
 | 
			
		||||
        return self::loadHotfix($source,$url);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static function loadFromService(ReaderInterface $service, $id)
 | 
			
		||||
    {
 | 
			
		||||
        $source = $service->read($id);
 | 
			
		||||
        return self::loadHotfix($source,$service->getName());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static function loadHotfix($source,$origin)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        // Check for a signature header 
 | 
			
		||||
        if (false === strpos($source, self::PGP_HEADER_TOKEN)) {
 | 
			
		||||
            $body = $source;
 | 
			
		||||
            $signature = new Signature($body,null);
 | 
			
		||||
        } else {
 | 
			
		||||
            list ($body, $sig) = explode(self::PGP_HEADER_TOKEN, $source);
 | 
			
		||||
            $sig = self::PGP_HEADER_TOKEN.$sig;
 | 
			
		||||
            $signature = new Signature($body,$sig);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        // Extract header next
 | 
			
		||||
        list ($header,$body) = explode("\n---\n", $body, 2);
 | 
			
		||||
        $header = new Header($header);
 | 
			
		||||
 | 
			
		||||
        $hotfix = new Hotfix($body, $header, $signature, $origin);
 | 
			
		||||
        return $hotfix;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,86 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace NoccyLabs\Hotfix\Hotfix;
 | 
			
		||||
 | 
			
		||||
class Loader
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    protected $signedBy;
 | 
			
		||||
 | 
			
		||||
    protected $loaders = [];
 | 
			
		||||
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
        $this->addLoader(new Loader\FileLoader());
 | 
			
		||||
        $this->addLoader(new Loader\HttpLoader());
 | 
			
		||||
        $this->addLoader(new Loader\GistLoader());
 | 
			
		||||
        $this->addLoader(new Loader\PastebinLoader());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function addLoader(Loader\LoaderInterface $loader)
 | 
			
		||||
    {
 | 
			
		||||
        $this->loaders[] = $loader;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getLoaders()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->loaders;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function load($fix, $insecure=false)
 | 
			
		||||
    {
 | 
			
		||||
        foreach ($this->loaders as $loader) {
 | 
			
		||||
            $hotfix = $loader->load($fix);
 | 
			
		||||
            if ($hotfix === false) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            $sigHeader = '-----BEGIN PGP SIGNATURE-----';
 | 
			
		||||
            if (false === strpos($hotfix, $sigHeader)) {
 | 
			
		||||
                if (!$insecure) {
 | 
			
		||||
                    throw new \Exception("Hotfix is not signed");
 | 
			
		||||
                }
 | 
			
		||||
                $body = $hotfix;
 | 
			
		||||
                $signer = null;
 | 
			
		||||
            } else {
 | 
			
		||||
                list ($body, $signature) = explode($sigHeader, $hotfix);
 | 
			
		||||
                $signature = $sigHeader.$signature;
 | 
			
		||||
                if (!$insecure) {
 | 
			
		||||
                    $signer = $this->verifySignature($body, $signature);
 | 
			
		||||
                } else {
 | 
			
		||||
                    $signer = null;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return new Hotfix($body, $signer);
 | 
			
		||||
        }
 | 
			
		||||
        fprintf(STDERR, "Error: Couldn't load '%s'\n", $fix);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function verifySignature($body, $signature)
 | 
			
		||||
    {
 | 
			
		||||
        $gpg = gnupg_init();
 | 
			
		||||
 | 
			
		||||
        $sigInfo = gnupg_verify($gpg, $body, $signature);
 | 
			
		||||
 | 
			
		||||
        if ($sigInfo === false) {
 | 
			
		||||
            throw new \Exception("Hotfix signature is not valid!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $fingerprint = $sigInfo[0]['fingerprint'];
 | 
			
		||||
        $keyInfo = gnupg_keyinfo($gpg, $fingerprint);
 | 
			
		||||
 | 
			
		||||
        if (empty($keyInfo)) {
 | 
			
		||||
            throw new \Exception("Unknown signer (key id {$sigInfo[0]['fingerprint']})");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $subKeys = $keyInfo[0]['subkeys'];
 | 
			
		||||
        $keyId = null;
 | 
			
		||||
        foreach ($subKeys as $subKey) {
 | 
			
		||||
            if ($subKey['fingerprint'] == $fingerprint) {
 | 
			
		||||
                $keyId = $subKey['keyid'];
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return [ $keyInfo[0], $keyId ];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										98
									
								
								src/Hotfix/Signature.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								src/Hotfix/Signature.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace NoccyLabs\Hotfix\Hotfix;
 | 
			
		||||
 | 
			
		||||
use Symfony\Component\Yaml\Yaml;
 | 
			
		||||
 | 
			
		||||
class Signature
 | 
			
		||||
{
 | 
			
		||||
    /** @var bool Whether the signature is valid  */
 | 
			
		||||
    protected $valid;
 | 
			
		||||
 | 
			
		||||
    /** @var string|null The name of the key used to sign */
 | 
			
		||||
    protected $signer;
 | 
			
		||||
 | 
			
		||||
    /** @var string|null The ID of the key used to sign */
 | 
			
		||||
    protected $keyId;
 | 
			
		||||
 | 
			
		||||
    protected $error;
 | 
			
		||||
 | 
			
		||||
    protected $body;
 | 
			
		||||
 | 
			
		||||
    protected $signature;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructor
 | 
			
		||||
     *
 | 
			
		||||
     * @param bool $valid Whether the signature is valid
 | 
			
		||||
     * @param string $signer For a valid signature, the name of the signer
 | 
			
		||||
     * @param string $keyId For a valid signature, the key ID
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct($body, $signature)
 | 
			
		||||
    {
 | 
			
		||||
        $this->body = $body;
 | 
			
		||||
        $this->signature = $signature;
 | 
			
		||||
        $this->verify();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function verify()
 | 
			
		||||
    {
 | 
			
		||||
        if (!$this->signature) {
 | 
			
		||||
            $this->error = "Hotfix is not signed!";
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $gpg = gnupg_init();
 | 
			
		||||
 | 
			
		||||
        $sigInfo = gnupg_verify($gpg, $this->body, $this->signature);
 | 
			
		||||
 | 
			
		||||
        if ($sigInfo === false) {
 | 
			
		||||
            $this->error = "Invalid signature";
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $fingerprint = $sigInfo[0]['fingerprint'];
 | 
			
		||||
        $keyInfo = gnupg_keyinfo($gpg, $fingerprint);
 | 
			
		||||
 | 
			
		||||
        if (empty($keyInfo)) {
 | 
			
		||||
            $this->error = "Unknown signer (key id {$sigInfo[0]['fingerprint']})";
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $subKeys = $keyInfo[0]['subkeys'];
 | 
			
		||||
        $keyId = null;
 | 
			
		||||
        foreach ($subKeys as $subKey) {
 | 
			
		||||
            if ($subKey['fingerprint'] == $fingerprint) {
 | 
			
		||||
                $keyId = $subKey['keyid'];
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $signerInfo = sprintf("%s (%s)", $keyInfo[0]['uids'][0]['name'], $keyInfo[0]['uids'][0]['email']);
 | 
			
		||||
 | 
			
		||||
        $this->valid = true;
 | 
			
		||||
        $this->signer = $signerInfo;
 | 
			
		||||
        $this->keyId = $keyId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function isValid()
 | 
			
		||||
    {
 | 
			
		||||
        return ($this->valid === true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getSigner()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->signer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getKeyId()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->keyId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getError()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->error;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -13,12 +13,40 @@ use NoccyLabs\Hotfix\Hotfix\Hotfix;
 | 
			
		||||
class BashRunner implements RunnerInterface
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    const BASH_STUB = "/../stubs/bash.stub";
 | 
			
		||||
 | 
			
		||||
    protected $hotfix;
 | 
			
		||||
 | 
			
		||||
    protected $facts;
 | 
			
		||||
 | 
			
		||||
    public function prepare(Hotfix $hotfix, Facts $facts)
 | 
			
		||||
    {
 | 
			
		||||
        $this->hotfix = $hotfix;
 | 
			
		||||
        $this->facts = $facts;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function apply()
 | 
			
		||||
    {
 | 
			
		||||
        $head = file_get_contents(__DIR__.self::BASH_STUB);
 | 
			
		||||
        $body = $this->hotfix->getBody();
 | 
			
		||||
        $hash = $this->hotfix->getHash();
 | 
			
		||||
 | 
			
		||||
        $facts = $this->facts->getFlat();
 | 
			
		||||
        $head .= 'function fact {'.PHP_EOL;
 | 
			
		||||
        $head .= '  case "$1" in'.PHP_EOL;
 | 
			
		||||
        foreach ($facts as $key=>$fact) {
 | 
			
		||||
            $head .= '  "'.$key.'") echo "'.$fact.'";;'.PHP_EOL;
 | 
			
		||||
        }
 | 
			
		||||
        $head .= '  esac'.PHP_EOL;
 | 
			
		||||
        $head .= '}'.PHP_EOL;
 | 
			
		||||
 | 
			
		||||
        // Create temporary filename based on the hash of the hotfix
 | 
			
		||||
        $tmpfile = sys_get_temp_dir()."/hotfix_".$hash;
 | 
			
		||||
        file_put_contents($tmpfile, $head."\n".$body."\n");
 | 
			
		||||
 | 
			
		||||
        // Execute the hotfix and clean up
 | 
			
		||||
        passthru("bash {$tmpfile}");
 | 
			
		||||
        unlink($tmpfile);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -13,12 +13,40 @@ use NoccyLabs\Hotfix\Hotfix\Hotfix;
 | 
			
		||||
class PhpRunner implements RunnerInterface
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    const PHP_STUB = "/../stubs/php.stub";
 | 
			
		||||
 | 
			
		||||
    protected $hotfix;
 | 
			
		||||
 | 
			
		||||
    protected $facts;
 | 
			
		||||
 | 
			
		||||
    public function prepare(Hotfix $hotfix, Facts $facts)
 | 
			
		||||
    {
 | 
			
		||||
        $this->hotfix = $hotfix;
 | 
			
		||||
        $this->facts = $facts;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function apply()
 | 
			
		||||
    {
 | 
			
		||||
        $stub = file_get_contents(__DIR__.self::PHP_STUB);
 | 
			
		||||
        $body = $this->hotfix->getBody();
 | 
			
		||||
        $hash = $this->hotfix->getHash();
 | 
			
		||||
 | 
			
		||||
        $stub.= 'function fact($key) { ';
 | 
			
		||||
        $stub.= 'switch ($key) {';
 | 
			
		||||
        $facts = $this->facts->getFlat();
 | 
			
		||||
        foreach ($facts as $key=>$value) {
 | 
			
		||||
            $stub.= 'case "'.$key.'": return "'.$value.'";';
 | 
			
		||||
        }
 | 
			
		||||
        $stub.= '}}'.PHP_EOL;
 | 
			
		||||
 | 
			
		||||
        // Create temporary filename based on the hash of the hotfix filename
 | 
			
		||||
        $tmpfile = sys_get_temp_dir()."/hotfix_".$hash;
 | 
			
		||||
        file_put_contents($tmpfile, '<?php '.$stub."\n".$body."\n");
 | 
			
		||||
 | 
			
		||||
        // Execute the hotfix and clean up
 | 
			
		||||
        passthru("php {$tmpfile}");
 | 
			
		||||
        unlink($tmpfile);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -12,8 +12,25 @@ class RunnerFactory
 | 
			
		||||
    public static function createRunner(Hotfix $hotfix)
 | 
			
		||||
    {
 | 
			
		||||
        $facts = Facts::getSystemFacts();
 | 
			
		||||
        $meta = $hotfix->getHeader();
 | 
			
		||||
 | 
			
		||||
        switch ($meta->getLanguage()) {
 | 
			
		||||
            case 'php':
 | 
			
		||||
                $runner = new PhpRunner();
 | 
			
		||||
                break;
 | 
			
		||||
            case 'bash':
 | 
			
		||||
                $runner = new BashRunner();
 | 
			
		||||
                break;
 | 
			
		||||
            case 'python':
 | 
			
		||||
                $runner = new PythonRunner();
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
                throw new UnsupportedRunnerException("This version of hotfix doesn't support the runner ".$meta->getLanguage());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $runner->prepare($hotfix, $facts);
 | 
			
		||||
 | 
			
		||||
        return $runner;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
@@ -9,6 +9,8 @@ use NoccyLabs\Hotfix\Hotfix\Hotfix;
 | 
			
		||||
interface RunnerInterface
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    public function applyHotfix(Hotfix $hotfix, Facts $facts);
 | 
			
		||||
    public function prepare(Hotfix $hotfix, Facts $facts);
 | 
			
		||||
 | 
			
		||||
    public function apply();
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								src/Service/IxService.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/Service/IxService.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace NoccyLabs\Hotfix\Service;
 | 
			
		||||
 | 
			
		||||
class IxService implements ServiceInterface, ReaderInterface, PublisherInterface
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    public function getId()
 | 
			
		||||
    {
 | 
			
		||||
        return "ix";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getInfo()
 | 
			
		||||
    {
 | 
			
		||||
        return "Use the ix.io pastebin for accessing patches";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function publish(Hotfix $hotfix)
 | 
			
		||||
    {
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function read($url)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								src/Service/PublisherInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/Service/PublisherInterface.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace NoccyLabs\Hotfix\Service;
 | 
			
		||||
 | 
			
		||||
interface PublisherInterface
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								src/Service/ReaderInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/Service/ReaderInterface.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace NoccyLabs\Hotfix\Service;
 | 
			
		||||
 | 
			
		||||
interface ReaderInterface
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								src/Service/ServiceInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/Service/ServiceInterface.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace NoccyLabs\Hotfix\Service;
 | 
			
		||||
 | 
			
		||||
interface ServiceInterface
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								src/Service/ServiceManager.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/Service/ServiceManager.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace NoccyLabs\Hotfix\Service;
 | 
			
		||||
 | 
			
		||||
class ServiceManager
 | 
			
		||||
{
 | 
			
		||||
    private static $services = [];
 | 
			
		||||
 | 
			
		||||
    public static function registerService(ServiceInterface $service)
 | 
			
		||||
    {
 | 
			
		||||
        self::$services[$service->getId()] = $service;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function getRegisteredServices()
 | 
			
		||||
    {
 | 
			
		||||
        return self::$services;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function getService($id)
 | 
			
		||||
    {
 | 
			
		||||
        if (!array_key_exists($id,self::$services)) return null;
 | 
			
		||||
        return self::$services[$id];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user