summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Client/Config/Loader.php (renamed from src/Config/Loader.php)0
-rw-r--r--src/Client/Filesystem/CreateDirectory.php (renamed from src/Filesystem/CreateDirectory.php)0
-rw-r--r--src/Client/Filesystem/CreateFile.php (renamed from src/Filesystem/CreateFile.php)0
-rw-r--r--src/Client/Script/Command/Site/Create.php (renamed from src/Script/Command/Site/Create.php)0
-rw-r--r--src/Client/Script/Console.php (renamed from src/Script/Console.php)0
-rw-r--r--src/Client/Task/TaskInterface.php (renamed from src/Task/TaskInterface.php)0
-rw-r--r--src/Manager/Config/Loader.php150
-rw-r--r--src/Manager/Filesystem/CreateDirectory.php49
-rw-r--r--src/Manager/Filesystem/CreateFile.php65
-rw-r--r--src/Manager/Script/Command/Site/Create.php348
-rw-r--r--src/Manager/Script/Console.php24
-rw-r--r--src/Manager/Task/TaskInterface.php11
12 files changed, 647 insertions, 0 deletions
diff --git a/src/Config/Loader.php b/src/Client/Config/Loader.php
index 97df62e..97df62e 100644
--- a/src/Config/Loader.php
+++ b/src/Client/Config/Loader.php
diff --git a/src/Filesystem/CreateDirectory.php b/src/Client/Filesystem/CreateDirectory.php
index 2621169..2621169 100644
--- a/src/Filesystem/CreateDirectory.php
+++ b/src/Client/Filesystem/CreateDirectory.php
diff --git a/src/Filesystem/CreateFile.php b/src/Client/Filesystem/CreateFile.php
index ce9537f..ce9537f 100644
--- a/src/Filesystem/CreateFile.php
+++ b/src/Client/Filesystem/CreateFile.php
diff --git a/src/Script/Command/Site/Create.php b/src/Client/Script/Command/Site/Create.php
index df9fc18..df9fc18 100644
--- a/src/Script/Command/Site/Create.php
+++ b/src/Client/Script/Command/Site/Create.php
diff --git a/src/Script/Console.php b/src/Client/Script/Console.php
index 5f5d90d..5f5d90d 100644
--- a/src/Script/Console.php
+++ b/src/Client/Script/Console.php
diff --git a/src/Task/TaskInterface.php b/src/Client/Task/TaskInterface.php
index 407e6c8..407e6c8 100644
--- a/src/Task/TaskInterface.php
+++ b/src/Client/Task/TaskInterface.php
diff --git a/src/Manager/Config/Loader.php b/src/Manager/Config/Loader.php
new file mode 100644
index 0000000..97df62e
--- /dev/null
+++ b/src/Manager/Config/Loader.php
@@ -0,0 +1,150 @@
+<?php
+
+namespace App\Config;
+
+/**
+ * A class to load a config into an array
+ * Throws an exception if it fails to laod
+ *
+ * @author Phil Burton <phil@pgburton.com>
+ */
+class Loader
+{
+ /**
+ * A loaded config array
+ *
+ * @var mixed[]
+ */
+ protected $config;
+
+ /**
+ * Try and load a config
+ *
+ * @author Phil Burton <phil@pgburton.com>
+ */
+ public function __construct()
+ {
+ foreach ($this->getConfigPaths() as $path) {
+ if ($config = $this->loadConfig($path)) {
+ $this->validate();
+ $this->clean();
+ return;
+ }
+ }
+
+ // No config found
+ throw new \Exception('Could not find config file.');
+ }
+
+ /**
+ * Try and load a config file
+ * If we can't return false
+ *
+ * @author Phil Burton <phil@pgburton.com>
+ * @return mixed[]|false
+ */
+ public function loadConfig(string $path)
+ {
+ $filename = $path . '/' . $this->getConfigFilename();
+
+ if (!$this->config) {
+ if (!file_exists($filename)) {
+ return false;
+ }
+
+ if (!is_readable($filename)) {
+ return false;
+ }
+
+ if (!$config = include($filename)) {
+ return false;
+ }
+
+ $this->config = $config;
+ }
+
+ return $this->config;
+ }
+
+ /**
+ * Return the nsam of the config file to load
+ *
+ * @author Phil Burton <phil@pgburton.com>
+ * @return string;
+ */
+ public function getConfigFilename()
+ {
+ return 'dipper.php';
+ }
+
+ /**
+ * Make sure the config is up to scratch
+ *
+ * @author Phil Burton <phil@pgburton.com>
+ */
+ public function validate()
+ {
+ $config = $this->getConfig();
+
+ foreach ($this->getRequired() as $required) {
+ if (!isset($config[$required])) {
+ throw new \Exception("Could not find " . $required . " in config file.");
+ }
+ }
+ }
+
+ /**
+ * Clean up the config ready for use
+ *
+ * @author Phil Burton <phil@pgburton.com>
+ */
+ public function clean()
+ {
+ $config = $this->getConfig();
+ foreach ($config as &$item) {
+ // Remove trailing slashes
+ $item = rtrim($item, "/");
+ }
+
+ $this->config = $config;
+ }
+
+ /**
+ * Return the array of config paths
+ *
+ * @author Phil Burton <phil@pgburton.com>
+ * @return string[]
+ */
+ public function getConfigPaths()
+ {
+ return [
+ realpath(dirname(__FILE__) . "/../../"), // Root of dipper
+ realpath(dirname(__FILE__) . "/../../config") // Config directory in dipper
+ ];
+ }
+
+ /**
+ * Return the loaded config
+ *
+ * @author Phil Burton <phil@pgburton.com>
+ * @return mixed[]
+ */
+ public function getConfig()
+ {
+ return $this->config;
+ }
+
+ /**
+ * Return the required config keys
+ *
+ * @author Phil Burton <phil@pgburton.com>
+ * @return string[]
+ */
+ public function getRequired()
+ {
+ return [
+ "SITES_ROOT",
+ "CONFIG_ROOT"
+ ];
+ }
+}
diff --git a/src/Manager/Filesystem/CreateDirectory.php b/src/Manager/Filesystem/CreateDirectory.php
new file mode 100644
index 0000000..2621169
--- /dev/null
+++ b/src/Manager/Filesystem/CreateDirectory.php
@@ -0,0 +1,49 @@
+<?php
+
+namespace App\Filesystem;
+
+use App\Task\TaskInterface;
+
+/**
+ * Class to create a new directory
+ *
+ * @author Phil Burton <phil@d3r.com>
+ */
+class CreateDirectory implements TaskInterface
+{
+ /**
+ * Directory to create
+ *
+ * @var string
+ */
+ protected $directory;
+
+ /**
+ * Check if the directory already exists
+ *
+ * @param string $filename
+ * @author Phil Burton <phil@d3r.com>
+ */
+ public function __construct(string $directory)
+ {
+ $this->directory = $directory;
+
+ if (!is_writable(dirname($directory))) {
+ throw new \Exception('Cannot create directory at: ' . $directory);
+ }
+
+ if (file_exists($directory)) {
+ throw new \Exception('Directory already exists at: ' . $directory);
+ }
+ }
+
+ /**
+ * Create the new directory
+ *
+ * @author Phil Burton <phil@d3r.com>
+ */
+ public function execute()
+ {
+ mkdir($this->directory);
+ }
+}
diff --git a/src/Manager/Filesystem/CreateFile.php b/src/Manager/Filesystem/CreateFile.php
new file mode 100644
index 0000000..ce9537f
--- /dev/null
+++ b/src/Manager/Filesystem/CreateFile.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace App\Filesystem;
+
+use App\Task\TaskInterface;
+
+/**
+ * Class to create a new file
+ *
+ * @author Phil Burton <phil@d3r.com>
+ */
+class CreateFile implements TaskInterface
+{
+ /**
+ * Name of file to create
+ *
+ * @var string
+ */
+ protected $filename;
+
+ /**
+ * File contents to write
+ *
+ * @var string
+ */
+ protected $contents;
+
+ /**
+ * Check if the file already exists
+ *
+ * @param string $filename
+ * @author Phil Burton <phil@d3r.com>
+ */
+ public function __construct(string $filename, $contents = false)
+ {
+ $this->filename = $filename;
+
+ if ($contents) {
+ $this->contents = $contents;
+ }
+
+ if (!is_writable(dirname($filename))) {
+ throw new \Exception('Cannot create file at: ' . $filename);
+ }
+
+ if (file_exists($filename)) {
+ throw new \Exception('File already exists at: ' . $filename);
+ }
+ }
+
+ /**
+ * Create the new file
+ *
+ * @author Phil Burton <phil@d3r.com>
+ */
+ public function execute()
+ {
+ touch($this->filename);
+
+ $contents = $this->contents;
+ if ($contents) {
+ file_put_contents($this->filename, $contents);
+ }
+ }
+}
diff --git a/src/Manager/Script/Command/Site/Create.php b/src/Manager/Script/Command/Site/Create.php
new file mode 100644
index 0000000..df9fc18
--- /dev/null
+++ b/src/Manager/Script/Command/Site/Create.php
@@ -0,0 +1,348 @@
+<?php
+
+namespace App\Script\Command\Site;
+
+use Symfony\Component\Console\Command\Command as SyCommand;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Helper\ProgressBar;
+use App\Filesystem\CreateFile;
+use App\Filesystem\CreateDirectory;
+use App\Task\TaskInterface;
+
+/**
+ * A new Symfony command for creating a new site deployment
+ *
+ * @author Phil Burton <phil@d3r.com>
+ */
+class Create extends SyCommand
+{
+ /**
+ * Symfony Progress Bar for command
+ *
+ * @var Symfony\Component\Console\Helper\ProgressBar
+ */
+ protected $progressBar;
+
+ /**
+ * Array of task sets containing tasks
+ *
+ * @var mixed
+ */
+ protected $tasks;
+
+ /**
+ * Name of the deployment
+ *
+ * @var string
+ */
+ protected $name;
+
+ /**
+ * Domain name of the deployment
+ *
+ * @var string
+ */
+ protected $domain;
+
+ /**
+ * Configure the command
+ *
+ * @author Phil Burton <phil@d3r.com>
+ */
+ protected function configure()
+ {
+ $this->addArgument('name', InputArgument::REQUIRED, 'The name of the new site.');
+ $this->addArgument('domain', InputArgument::REQUIRED, 'The domain name of the new site.');
+
+ $this
+ ->setName('site:create')
+ ->setDescription('Create a new site.')
+ ->setHelp('This command allows you to create a new site.');
+
+ $this->addOption(
+ 'test',
+ 't',
+ InputOption::VALUE_NONE,
+ 'Run in test mode without any file or directory created?'
+ );
+
+ $this->addOption(
+ 'ignore-config',
+ 'c',
+ InputOption::VALUE_NONE,
+ 'Ignore writing the config?'
+ );
+
+ $this->addOption(
+ 'ignore-filesystem',
+ 'f',
+ InputOption::VALUE_NONE,
+ 'Ignore writing the deployment files and directories?'
+ );
+ }
+
+ /**
+ * Run the command
+ *
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @author Phil Burton <phil@d3r.com>
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $taskCount = 9;
+ if ($input->getOption('ignore-filesystem')) {
+ $taskCount -= 8;
+ }
+
+ if ($input->getOption('ignore-config')) {
+ $taskCount -= 1;
+ }
+
+ if ($taskCount <= 0) {
+ echo "Nothing to do.\n";
+ exit;
+ }
+
+ $this->name = $input->getArgument('name');
+ $this->domain = $input->getArgument('domain');
+
+ $output->writeln(
+ 'Creating new site with name: '
+ . $input->getArgument('name')
+ . ' and domain: '
+ . $input->getArgument('domain')
+ );
+
+ // Set-up progress bar
+ $this->progressBar = new ProgressBar($output, $taskCount);
+ $this->progressBar->setFormatDefinition('custom', ' %current%/%max% -- %message%');
+ $this->progressBar->setFormat('custom');
+ $this->progressBar->setMessage('Starting...');
+ $this->progressBar->start();
+ $this->progressBar->setMessage('Running pre-flight checks');
+
+ // Construct the file commands so we run checks first
+ $this->progressBar->advance();
+
+ try {
+ $this->runPreflightChecks($input);
+ } catch (\Exception $e) {
+ $this->complete($output, "Error with pre-flight checks:\n" . $e->getMessage());
+ }
+ try {
+ if (!$input->getOption('test')) {
+ if (!$input->getOption('ignore-config')) {
+ $this->createConfig($input);
+ }
+
+ if (!$input->getOption('ignore-filesystem')) {
+ $this->createFilesystem($input);
+ }
+ }
+ } catch (\Exception $e) {
+ $this->complete($output, "Unexpected Error creating files and directories:\n " . $e->getMessage());
+ }
+ // Finish up
+ $this->complete($output, 'Complete', true);
+ }
+
+ /**
+ * Show a message and end the program
+ * Optionally complete the progress bar
+ *
+ * @author Phil Burton <phil@pgburton.com>
+ * @param OutputInterface $output
+ * @param string $message
+ * @param boolean $completeProgressBar
+ */
+ public function complete(OutputInterface $output, string $message, $completeProgressBar = false)
+ {
+ if ($completeProgressBar) {
+ $this->progressBar->advance();
+ $this->progressBar->finish();
+ }
+
+ $output->writeln('');
+ $output->writeln($message);
+ exit;
+ }
+
+ /**
+ * Run the required tasks to check we can complete the full deployment
+ *
+ * @author Phil Burton <phil@pgburton.com>
+ * @param InputInterface $input
+ */
+ public function runPreflightChecks(InputInterface $input)
+ {
+ $ignoreFilesystem = $input->getOption('ignore-filesystem');
+ $ignoreConfig = $input->getOption('ignore-config');
+
+ if (!$ignoreFilesystem) {
+ $this->addTask(
+ 'check-filesystem',
+ 'Creating site directory',
+ new CreateDirectory(
+ $this->getFullSitesPath($this->name)
+ )
+ );
+ }
+
+ if (!$ignoreConfig) {
+ $this->addTask(
+ 'check-config',
+ 'Creating nginx config file',
+ new CreateFile(
+ CONFIG_ROOT . '/' . $this->name . '.conf',
+ include_once(DIPPER_ROOT . '/nginx/stub.php')
+ )
+ );
+ }
+ }
+
+ /**
+ * Run the creation of the config tasks
+ *
+ * @author Phil Burton <phil@pgburton.com>
+ */
+ public function createConfig()
+ {
+ $this->runTaskSet('check-config');
+ }
+
+ /**
+ * Run the creatuion of the filesystem tasks
+ *
+ * @author Phil Burton <phil@pgburton.com>
+ * @param InputInterface $input
+ */
+ public function createFilesystem(InputInterface $input)
+ {
+ $this->runTaskSet('check-filesystem');
+
+ $this->runTask(
+ 'Creating logs directory',
+ new CreateDirectory(
+ $this->getFullSitesPath($this->name) . '/logs'
+ ),
+ true
+ );
+
+ $this->runTask(
+ 'Creating access log file',
+ new CreateFile(
+ $this->getFullSitesPath($this->name) . '/logs/' . $this->name . '.access_log'
+ ),
+ true
+ );
+
+ $this->runTask(
+ 'Creating error log file',
+ new CreateFile(
+ $this->getFullSitesPath($this->name) . '/logs/' . $this->name . '.errors_log'
+ ),
+ true
+ );
+
+ $this->runTask(
+ 'Creating web folder',
+ new CreateDirectory(
+ $this->getFullSitesPath($this->name) . '/web'
+ ),
+ true
+ );
+
+ $this->runTask(
+ 'Creating directory index.php',
+ new CreateFile(
+ $this->getFullSitesPath($this->name) . '/web/index.php'
+ ),
+ true
+ );
+ }
+
+ /**
+ * Add a task to a task set
+ *
+ * @author Phil Burton <phil@pgburton.com>
+ * @param string $taskSetName
+ * @param string $taskName
+ * @param TaskInterface $task
+ */
+ public function addTask(string $taskSetName, string $taskName, TaskInterface $task)
+ {
+ $this->taskPriority[$taskSetName][] = $taskName;
+ $this->tasks[$taskSetName][$taskName] = $task;
+ }
+
+ /**
+ * Get the array of tasks from a taskset
+ *
+ * @author Phil Burton <phil@pgburton.com>
+ * @param string $taskSetName
+ * @return TaskInterface[]
+ */
+ public function getTaskSet(string $taskSetName)
+ {
+ $tasks = $this->tasks;
+ if (array_key_exists($taskSetName, $tasks)) {
+ return $tasks[$taskSetName];
+ }
+
+ return false;
+ }
+
+ /**
+ * Run all the tasks in a taskset
+ *
+ * @author Phil Burton <phil@pgburton.com>
+ * @param string $taskSetName]
+ * @param boolean $advanceProgressBar
+ */
+ public function runTaskSet(string $taskSetName, $advanceProgressBar = false)
+ {
+ $tasks = $this->getTaskSet($taskSetName);
+
+ if (!$tasks) {
+ throw new \Exception('Could not find task set `' . $taskSetName . '`');
+ }
+ foreach ($this->taskPriority[$taskSetName] as $message) {
+ $task = $tasks[$message];
+ // Create file in web root for execution
+ $this->runTask($message, $task, $advanceProgressBar);
+ }
+ }
+
+ /**
+ * Return the full path of a given file
+ *
+ * @author Phil Burton <phil@pgburton.com>
+ * @param string $path
+ * @return string
+ */
+ protected function getFullSitesPath($path)
+ {
+ return SITES_ROOT . "/" . $path;
+ }
+
+ /**
+ * Run a task
+ *
+ * @author Phil Burton <phil@pgburton.com>
+ * @param mixed $task
+ * @param string $message
+ * @return string
+ */
+ protected function runTask(string $message, TaskInterface $task, $advanceProgressBar = false)
+ {
+ if ($advanceProgressBar) {
+ $this->progressBar->advance();
+ $this->progressBar->setMessage($message);
+ }
+ $task->execute();
+ }
+}
diff --git a/src/Manager/Script/Console.php b/src/Manager/Script/Console.php
new file mode 100644
index 0000000..5f5d90d
--- /dev/null
+++ b/src/Manager/Script/Console.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace App\Script;
+
+use Symfony\Component\Console\Application;
+use App\Script\Command\Site\Create;
+
+/**
+ * Main application class
+ */
+class Console
+{
+ /**
+ * Create symfony application and add commands
+ *
+ * @author Phil Burton <phil@pgburton.com>
+ */
+ public function __construct()
+ {
+ $application = new Application();
+ $application->add(new Create());
+ $application->run();
+ }
+}
diff --git a/src/Manager/Task/TaskInterface.php b/src/Manager/Task/TaskInterface.php
new file mode 100644
index 0000000..407e6c8
--- /dev/null
+++ b/src/Manager/Task/TaskInterface.php
@@ -0,0 +1,11 @@
+<?php
+
+namespace App\Task;
+
+/**
+ * A simple task object that can be executed
+ */
+interface TaskInterface
+{
+ public function execute();
+}