| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| #!/bin/sh | ||
|
|
||
| # Copyright: Brandon Mitchell | ||
| # License: MIT | ||
| # Source: https://github.com/sudo-bmitch/docker-base/blob/master/bin/fix-perms | ||
|
|
||
| opt_h=0 | ||
| opt_r=0 | ||
|
|
||
| while getopts 'g:hru:' option; do | ||
| case $option in | ||
| g) opt_g="$OPTARG";; | ||
| h) opt_h=1;; | ||
| r) opt_r=1;; | ||
| u) opt_u="$OPTARG";; | ||
| esac | ||
| done | ||
| shift $(expr $OPTIND - 1) | ||
|
|
||
| if [ $# -lt 1 -o "$opt_h" = "1" -o \( -z "$opt_g" -a -z "$opt_u" \) ]; then | ||
| echo "Usage: $(basename $0) [opts] path" | ||
| echo " -g group_name: group name to adjust gid" | ||
| echo " -h: this help message" | ||
| echo " -r: recursively update uid/gid on root filesystem" | ||
| echo " -u user_name: user name to adjust uid" | ||
| echo "Either -u or -g must be provided in addition to a path. The uid and" | ||
| echo "gid of the path will be used to modify the uid/gid inside the" | ||
| echo "container. e.g.: " | ||
| echo " $0 -g app_group -u app_user -r /path/to/vol/data" | ||
| [ "$opt_h" = "1" ] && exit 0 || exit 1 | ||
| fi | ||
|
|
||
| if [ "$(id -u)" != "0" ]; then | ||
| echo "Root required for $(basename $0)" | ||
| exit 1 | ||
| fi | ||
|
|
||
| if [ ! -e "$1" ]; then | ||
| echo "File or directory does not exist, skipping fix-perms: $1" | ||
| exit 0 | ||
| fi | ||
|
|
||
| if ! type usermod >/dev/null 2>&1 || \ | ||
| ! type groupmod >/dev/null 2>&1; then | ||
| if type apk /dev/null 2>&1; then | ||
| echo "Warning: installing shadow, this should be included in your image" | ||
| apk add --no-cache shadow | ||
| else | ||
| echo "Commands usermod and groupmod are required." | ||
| exit 1 | ||
| fi | ||
| fi | ||
|
|
||
| set -e | ||
|
|
||
| # update the uid | ||
| if [ -n "$opt_u" ]; then | ||
| OLD_UID=$(getent passwd "${opt_u}" | cut -f3 -d:) | ||
| NEW_UID=$(stat -c "%u" "$1") | ||
| if [ "$OLD_UID" != "$NEW_UID" ]; then | ||
| echo "Changing UID of $opt_u from $OLD_UID to $NEW_UID" | ||
| usermod -u "$NEW_UID" -o "$opt_u" | ||
| if [ -n "$opt_r" ]; then | ||
| find / -xdev -user "$OLD_UID" -exec chown -h "$opt_u" {} \; | ||
| fi | ||
| fi | ||
| fi | ||
|
|
||
| # update the gid | ||
| if [ -n "$opt_g" ]; then | ||
| OLD_GID=$(getent group "${opt_g}" | cut -f3 -d:) | ||
| NEW_GID=$(stat -c "%g" "$1") | ||
| if [ "$OLD_GID" != "$NEW_GID" ]; then | ||
| echo "Changing GID of $opt_g from $OLD_GID to $NEW_GID" | ||
| groupmod -g "$NEW_GID" -o "$opt_g" | ||
| if [ -n "$opt_r" ]; then | ||
| find / -xdev -group "$OLD_GID" -exec chgrp -h "$opt_g" {} \; | ||
| fi | ||
| fi | ||
| fi |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| <?php | ||
|
|
||
| class MwddSpecial extends SpecialPage { | ||
|
|
||
| public function __construct() { | ||
| parent::__construct( 'Mwdd' ); | ||
| } | ||
|
|
||
| /** | ||
| * @see SpecialPage::execute | ||
| * | ||
| * @param string|null $subPage | ||
| */ | ||
| public function execute( $subPage ) { | ||
| parent::execute( $subPage ); | ||
| global $mwddServices; | ||
|
|
||
| $this->getOutput()->addHTML( "Which services are running?" ); | ||
| $this->getOutput()->addHTML( "</br>" ); | ||
| $this->getOutput()->addHTML( json_encode( $mwddServices ) ); | ||
| $this->getOutput()->addHTML( "</br>" ); | ||
| $this->getOutput()->addHTML( "How does DB lag look?" ); | ||
| $this->getOutput()->addHTML( "</br>" ); | ||
| $this->getOutput()->addHTML( json_encode( \MediaWiki\MediaWikiServices::getInstance()->getDBLoadBalancer()->getMaxLag()[1] ) ); | ||
|
|
||
| } | ||
|
|
||
| } |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,20 +1,30 @@ | ||
| #!/bin/sh | ||
|
|
||
| # Make sure the master db is ready | ||
| /wait-for-it.sh db-master:3306 | ||
|
|
||
| # Hide the current LocalSettings.php if it exists | ||
| if [ -f /var/www/mediawiki/LocalSettings.php ] | ||
| if [ -f /app/LocalSettings.php ] | ||
| then | ||
| mv /var/www/mediawiki/LocalSettings.php /var/www/mediawiki/LocalSettings.php.docker.tmp | ||
| mv /app/LocalSettings.php /app/LocalSettings.php.docker.tmp | ||
| fi | ||
|
|
||
| # Install the base Mediawiki tables on the db server & remove the generated LocalSettings.php | ||
| php /var/www/mediawiki/maintenance/install.php --dbuser root --dbpass toor --dbname $1 --dbserver db-master --lang en --pass dockerpass docker-$1 admin | ||
| rm /var/www/mediawiki/LocalSettings.php | ||
| php /app/maintenance/install.php --dbuser root --dbpass toor --dbname $1 --dbserver db-master --lang en --pass dockerpass docker-$1 admin | ||
|
|
||
| # Remove previous last generated file if it exists | ||
| if [ -f /app/LocalSettings.php.docker.lastgenereated ] | ||
| then | ||
| rm /app/LocalSettings.php.docker.lastgenereated | ||
| fi | ||
| # Move the generated LocalSettings file, but keep it around incase we want to look at it... | ||
| mv /app/LocalSettings.php /app/LocalSettings.php.docker.lastgenereated | ||
|
|
||
| # Move back the old LocalSettings if we had moved one! | ||
| if [ -f /var/www/mediawiki/LocalSettings.php.docker.tmp ] | ||
| if [ -f /app/LocalSettings.php.docker.tmp ] | ||
| then | ||
| mv /var/www/mediawiki/LocalSettings.php.docker.tmp /var/www/mediawiki/LocalSettings.php | ||
| mv /app/LocalSettings.php.docker.tmp /app/LocalSettings.php | ||
| fi | ||
|
|
||
| # Run update.php too | ||
| php /var/www/mediawiki/maintenance/update.php --wiki $1 --quick | ||
| php /app/maintenance/update.php --wiki $1 --quick |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| <?php | ||
| $specialPageAliases = []; | ||
| $specialPageAliases['en'] = [ | ||
| 'Mwdd' => [ 'Mwdd' ], | ||
| ]; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| #!/bin/bash | ||
| # Split from https://tarunlalwani.com/post/mysql-master-slave-using-docker/ | ||
| # This file grabs the position that we will want to start replication at and stores it in a file. | ||
| # This data is then used by the replica to start replicating | ||
|
|
||
| position_file=/mwdd-connector/master_position | ||
| file_file=/mwdd-connector/master_file | ||
|
|
||
| # Only save the data if the files don't already exist | ||
| # They might have been created during another container startup | ||
| if [ -e "$position_file" ]; then | ||
| echo "Position file already exists" | ||
| exit 0 | ||
| fi | ||
|
|
||
| echo "Waiting for mysql master to start" | ||
| /wait-for-it.sh db-master:3306 | ||
| # Wait and double check | ||
| sleep 1 | ||
| /wait-for-it.sh db-master:3306 | ||
|
|
||
| echo "* Get the binlog file and position" | ||
| MYSQL01_Position=$(eval "mysql --host db-master -uroot -p$MYSQL_MASTER_PASSWORD -e 'show master status \G' | grep Position | sed -n -e 's/^.*: //p'") | ||
| MYSQL01_File=$(eval "mysql --host db-master -uroot -p$MYSQL_MASTER_PASSWORD -e 'show master status \G' | grep File | sed -n -e 's/^.*: //p'") | ||
|
|
||
| echo "* Saving data to files" | ||
|
|
||
| echo $MYSQL01_Position > $position_file | ||
| echo $MYSQL01_File > $file_file |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| #!/bin/bash | ||
| # Modified from https://tarunlalwani.com/post/mysql-master-slave-using-docker/ | ||
|
|
||
| position_file=/mwdd-connector/master_position | ||
| file_file=/mwdd-connector/master_file | ||
|
|
||
| echo "Waiting for mysql replica to start" | ||
| /wait-for-it.sh db-master:3306 | ||
| /wait-for-it.sh db-replica:3306 | ||
| # Wait and double check | ||
| sleep 1 | ||
| /wait-for-it.sh db-master:3306 | ||
| /wait-for-it.sh db-replica:3306 | ||
|
|
||
| # TODO add resilience? and wait for the position file to be created...? | ||
| # But this is probably okay, as the replica will take a while to start anyway.. | ||
|
|
||
| # Only save the data if the files don't already exist | ||
| # They might have been created during another container startup | ||
| if [ ! -e "$position_file" ]; then | ||
| echo "Position file doesnt exist, can't start replication" | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "* Create replication user" | ||
|
|
||
| mysql --host db-replica -uroot -p$MYSQL_REPLICA_PASSWORD -AN -e 'STOP SLAVE;'; | ||
| mysql --host db-replica -uroot -p$MYSQL_MASTER_PASSWORD -AN -e 'RESET SLAVE ALL;'; | ||
|
|
||
| mysql --host db-master -uroot -p$MYSQL_MASTER_PASSWORD -AN -e "CREATE USER '$MYSQL_REPLICATION_USER'@'%';" | ||
| mysql --host db-master -uroot -p$MYSQL_MASTER_PASSWORD -AN -e "GRANT REPLICATION SLAVE ON *.* TO '$MYSQL_REPLICATION_USER'@'%' IDENTIFIED BY '$MYSQL_REPLICATION_PASSWORD';" | ||
| mysql --host db-master -uroot -p$MYSQL_MASTER_PASSWORD -AN -e 'flush privileges;' | ||
|
|
||
|
|
||
| echo "* Set MySQL01 as master on MySQL02" | ||
|
|
||
| # Grab the position that should have been set from the first step of db-configure when the master was created | ||
| MYSQL01_Position=$(<$position_file) | ||
| MYSQL01_File=$(<$file_file) | ||
|
|
||
| MASTER_IP=$(eval "getent hosts db-master|awk '{print \$1}'") | ||
| echo $MASTER_IP | ||
| mysql --host db-replica -uroot -p$MYSQL_REPLICA_PASSWORD -AN -e "CHANGE MASTER TO master_host='db-master', master_port=3306, \ | ||
| master_user='$MYSQL_REPLICATION_USER', master_password='$MYSQL_REPLICATION_PASSWORD', master_log_file='$MYSQL01_File', \ | ||
| master_log_pos=$MYSQL01_Position;" | ||
|
|
||
| echo "* Set MySQL02 as master on MySQL01" | ||
|
|
||
| MYSQL02_Position=$(eval "mysql --host db-replica -uroot -p$MYSQL_REPLICA_PASSWORD -e 'show master status \G' | grep Position | sed -n -e 's/^.*: //p'") | ||
| MYSQL02_File=$(eval "mysql --host db-replica -uroot -p$MYSQL_REPLICA_PASSWORD -e 'show master status \G' | grep File | sed -n -e 's/^.*: //p'") | ||
|
|
||
| REPLICA_IP=$(eval "getent hosts db-replica|awk '{print \$1}'") | ||
| echo $REPLICA_IP | ||
| mysql --host db-master -uroot -p$MYSQL_MASTER_PASSWORD -AN -e "CHANGE MASTER TO master_host='db-replica', master_port=3306, \ | ||
| master_user='$MYSQL_REPLICATION_USER', master_password='$MYSQL_REPLICATION_PASSWORD', master_log_file='$MYSQL02_File', \ | ||
| master_log_pos=$MYSQL02_Position;" | ||
|
|
||
| echo "* Start Replica on both Servers" | ||
| mysql --host db-replica -uroot -p$MYSQL_REPLICA_PASSWORD -AN -e "start slave;" | ||
|
|
||
| echo "Increase the max_connections to 1000" | ||
| mysql --host db-master -uroot -p$MYSQL_MASTER_PASSWORD -AN -e 'set GLOBAL max_connections=1000'; | ||
| mysql --host db-replica -uroot -p$MYSQL_REPLICA_PASSWORD -AN -e 'set GLOBAL max_connections=1000'; | ||
|
|
||
| mysql --host db-replica -uroot -p$MYSQL_MASTER_PASSWORD -e "show slave status \G" | ||
|
|
||
| echo "MySQL servers created!" | ||
| echo "--------------------" | ||
| echo | ||
| echo Variables available fo you :- | ||
| echo | ||
| echo MYSQL01_IP : db-master | ||
| echo MYSQL02_IP : db-replica |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| vendor |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| FROM composer:1.10 as composer | ||
|
|
||
| COPY ./composer.json /app/composer.json | ||
| COPY ./composer.lock /app/composer.lock | ||
| RUN composer install --no-dev --no-progress | ||
|
|
||
|
|
||
| FROM php:7.2-cli | ||
|
|
||
| # Just install docker-compose which will allow the control app to interact with the docker setup | ||
| RUN apt-get update && \ | ||
| apt-get install -y \ | ||
| # TODO does the container really need git? I mean it doesn't even need docker-compose really... | ||
| git && \ | ||
| curl -L "https://github.com/docker/compose/releases/download/1.25.5/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && \ | ||
| chmod +x /usr/local/bin/docker-compose | ||
|
|
||
| COPY --from=composer /app/vendor /mwdd-vendor | ||
|
|
||
| RUN echo "#!/bin/bash" >> /idle && echo "tail -f /dev/null" >> /idle && chmod +x /idle | ||
|
|
||
| WORKDIR /mwdd | ||
|
|
||
| # We don't need anything to be running, just for the container to be setup and running | ||
| # this needs to be running as mwdd uses docker-compose exec... (I couldn't make run work...) | ||
| ENTRYPOINT ["/idle"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| ## mwdd control application | ||
|
|
||
| This application has been written as a second iteration of the mediawiki-docker-development environment. | ||
|
|
||
| This has been written in PHP to be as close as possible to the MediaWiki world, in the hopes of PRs etc. | ||
|
|
||
| Having a single command to do all of the things in a nice way has been [talked about for a while](https://github.com/addshore/mediawiki-docker-dev/issues/84) | ||
|
|
||
| The future plan would be that the only requirement is docker and or docker-compose in order to use this solution (no local PHP needed), but the details of that have not yet been finalized. | ||
|
|
||
| #### Directories | ||
|
|
||
| - Command - CLI commands that the application exposes | ||
| - DockerCompose - Classes that relate to the value docker-composer yml files used by the system | ||
| - Files - Classes that relate to the various files and directories that the system interacts with | ||
| - Shell - Classes that relate to the various applications this application shells out to |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| #!/usr/bin/env php | ||
| <?php | ||
|
|
||
| error_reporting(E_ALL); | ||
| ini_set('display_errors', 1); | ||
|
|
||
| if ( $_SERVER['PHP_SELF'] !== 'control/app.php' ) { | ||
| echo "You are running the control app from the wrong context.\n"; | ||
| echo "Please run the app from the root mediawiki-docker-dev directory.\n"; | ||
| die(); | ||
| } | ||
|
|
||
| if(file_exists(__DIR__.'/vendor/autoload.php')){ | ||
| // Load a local vendor dir if it exits | ||
| require_once __DIR__.'/vendor/autoload.php'; | ||
| } elseif( file_exists('/mwdd-vendor') ) { | ||
| // If we are running in the control container, we can just copy the vendor that we made when building the image. | ||
| shell_exec('cp -R /mwdd-vendor ' . __DIR__ . '/vendor'); // XXX FIXME: this will copy as root? | ||
| // Try again with our copied vendor dir from the control image | ||
| require_once __DIR__.'/vendor/autoload.php'; | ||
| } else { | ||
| echo "You either need to:\n"; | ||
| echo " - Use a php environment locally and have done a composer install of the control directory."; | ||
| echo " - Use a docker-compose environment which will populate the control vendor directory for you. (as root FIXME)"; | ||
| die(); | ||
| } | ||
|
|
||
| define('MWDD_DIR', dirname( __DIR__ )); | ||
|
|
||
| $application = new \Symfony\Component\Console\Application('mwdd'); | ||
|
|
||
| $application->add(new \Addshore\Mwdd\Command\Base\HostsAdd()); | ||
|
|
||
| // TODO register these using a factory or something... | ||
| $mwHelp = <<<EOH | ||
| MediaWiki. | ||
| MediaWiki will be accessible at a location such as: http://default.web.mw.localhost:8080/api.php | ||
| EOH; | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Create('mw', $mwHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Suspend('mw', $mwHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Resume('mw', $mwHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Exec('mw', $mwHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Logs('mw', $mwHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\MediaWiki\GetCode()); | ||
| $application->add(new \Addshore\Mwdd\Command\MediaWiki\PHPUnit()); | ||
| $application->add(new \Addshore\Mwdd\Command\MediaWiki\Composer()); | ||
| $application->add(new \Addshore\Mwdd\Command\MediaWiki\Fresh()); | ||
| $application->add(new \Addshore\Mwdd\Command\MediaWiki\Maint()); | ||
| $application->add(new \Addshore\Mwdd\Command\MediaWiki\Quibble()); | ||
| $application->add(new \Addshore\Mwdd\Command\MediaWiki\Install()); | ||
|
|
||
| $adminerHelp = 'Adminer is a tool for managing content in MySQL databases.'; | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Create('adminer', $adminerHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Suspend('adminer', $adminerHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Resume('adminer', $adminerHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Exec('adminer', $adminerHelp)); | ||
|
|
||
| $phpMyAdminHelp = 'phpMyAdmin is a free and open source administration tool for MySQL and MariaDB.'; | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Create('phpmyadmin', $phpMyAdminHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Suspend('phpmyadmin', $phpMyAdminHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Resume('phpmyadmin', $phpMyAdminHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Exec('phpmyadmin', $phpMyAdminHelp)); | ||
|
|
||
| $redisHelp = 'Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker.'; | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Create('redis', $redisHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Suspend('redis', $redisHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Resume('redis', $redisHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Exec('redis', $redisHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Cli('redis', 'redis-cli', $redisHelp)); | ||
|
|
||
| $statsdHelp = 'Statsd and Graphite allow for simple time series data collection.'; | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Create('statsd', $statsdHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Suspend('statsd', $statsdHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Resume('statsd', $statsdHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Exec('statsd', $statsdHelp)); | ||
|
|
||
| $masterHelp = <<<EOH | ||
| A primary MySql server (master). | ||
| You can alter the image that is used in you local.env file. | ||
| EOH; | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Create('db', $masterHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Suspend('db', $masterHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Resume('db', $masterHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Exec('db', $masterHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Cli('db', 'mysql', $masterHelp)); | ||
|
|
||
| $replicaHelp = <<< EOH | ||
| A second MySql server with automatic replication from the master. | ||
| You can alter the image that is used in you local.env file. | ||
| Upon startup it might take a short while for server to catch up with the master, depending on how much data has been written. | ||
| You can check the replication status using <info>SHOW SLAVE STATUS</info> | ||
| EOH; | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Create('db-replica', $replicaHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Suspend('db-replica', $replicaHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Resume('db-replica', $replicaHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Exec('db-replica', $replicaHelp)); | ||
| $application->add(new \Addshore\Mwdd\Command\ServiceBase\Cli('db-replica', 'mysql', $replicaHelp)); | ||
|
|
||
| $application->add(new \Addshore\Mwdd\Command\DockerCompose\Raw()); | ||
| $application->add(new \Addshore\Mwdd\Command\DockerCompose\Ps()); | ||
| $application->add(new \Addshore\Mwdd\Command\DockerCompose\Logs()); | ||
| $application->add(new \Addshore\Mwdd\Command\DockerCompose\Destroy()); | ||
| $application->add(new \Addshore\Mwdd\Command\DockerCompose\Bash()); | ||
|
|
||
| $application->add(new \Addshore\Mwdd\Command\Control\Create()); | ||
| $application->add(new \Addshore\Mwdd\Command\Control\Suspend()); | ||
| $application->add(new \Addshore\Mwdd\Command\Control\Bash()); | ||
|
|
||
| $application->run(); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| { | ||
| "require": { | ||
| "symfony/console": "^5.0", | ||
| "m1/env": "^2.2", | ||
| "symfony/yaml": "^5.0" | ||
| }, | ||
| "autoload": { | ||
| "psr-4": { | ||
| "Addshore\\Mwdd\\": "src/" | ||
| } | ||
| } | ||
| } |
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\Base; | ||
|
|
||
| use Addshore\Mwdd\DockerCompose\Base; | ||
| use Addshore\Mwdd\Files\DotEnv; | ||
| use Addshore\Mwdd\Shell\Docker; | ||
| use Addshore\Mwdd\Shell\DockerCompose; | ||
| use Addshore\Mwdd\Shell\Id; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\ArrayInput; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class Create extends Command | ||
| { | ||
|
|
||
| protected static $defaultName = 'baseXXX:create'; | ||
|
|
||
| protected function configure() | ||
| { | ||
| $this->setDescription('Create a the most basic development environment.'); | ||
| $serviceString = implode( ', ', Base::SERVICES ); | ||
| $this->setHelp(<<< EOT | ||
| Creates the most basic development environment, with the following services: | ||
| ${serviceString} | ||
| EOT | ||
| ); | ||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output) | ||
| { | ||
| (new DotEnv())->updateFromDefaultAndLocal(); | ||
|
|
||
| # Start containers | ||
| $output->writeln('Starting services: ' . implode( ',', Base::SERVICES )); | ||
| (new DockerCompose())->upDetached( Base::SERVICES ); | ||
|
|
||
| # Add document root index file (NOTE: docker-compose lacks a "cp" command) | ||
| # TODO why is this not just in the docker-compose yml? | ||
| (new Docker())->cp( | ||
| 'config/mediawiki/index.php', | ||
| (new DockerCompose())->psQ(Base::SRV_MEDIAWIKI) . '://var/www/index.php' | ||
| ); | ||
|
|
||
| # Chown some things... | ||
| # TODO should this be in the entrypoint? YES! | ||
| (new DockerCompose())->exec( | ||
| Base::SRV_MEDIAWIKI, | ||
| 'chmod 777 //var/log/mediawiki //var/www/mediawiki/images/docker', | ||
| '--user root' | ||
| ); | ||
|
|
||
| # Wait for the db server | ||
| $output->writeln('Waiting for the db server'); | ||
| $output->writeln('Sometimes this can take some time...'); | ||
| (new DockerCompose())->exec( Base::SRV_MEDIAWIKI, '//srv/wait-for-it.sh db-master:3306' ); | ||
|
|
||
| # Reset local hosts file | ||
| if(file_exists(MWDD_DIR . '/.hosts')) { | ||
| unlink( MWDD_DIR . '/.hosts' ); | ||
| } | ||
| $this->getApplication()->find('base:hosts-add')->run( new ArrayInput([ 'host' => 'proxy.mw.localhost' ]), $output ); | ||
|
|
||
| $this->getApplication()->find('mw:installsite')->run( new ArrayInput([ 'site' => 'default' ]), $output ); | ||
|
|
||
| $output->writeln('Your development environment is running'); | ||
| $output->writeln('You may need to update your hosts file (see .hosts and hosts-sync files)!!'); | ||
|
|
||
| return 0; | ||
|
|
||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\Base; | ||
|
|
||
| use Addshore\Mwdd\Files\DotHosts; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class HostsAdd extends Command | ||
| { | ||
|
|
||
| protected static $defaultName = 'base:hosts-add'; | ||
|
|
||
| protected function configure() | ||
| { | ||
| $this->setHidden(true); | ||
| $this->addArgument( 'host' ); | ||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output) | ||
| { | ||
| $host = $input->getArgument( 'host' ); | ||
| (new DotHosts())->addHost( '127.0.0.1', $host ); | ||
| return 0; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\Control; | ||
|
|
||
| use Addshore\Mwdd\DockerCompose\Control; | ||
| use Addshore\Mwdd\Shell\DockerCompose; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class Bash extends Command | ||
| { | ||
|
|
||
| protected static $defaultName = 'ctrl:bash'; | ||
|
|
||
| protected function configure() | ||
| { | ||
| $this->setDescription('Runs bash in the control container (if running).'); | ||
| $this->setHidden(true); | ||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output) | ||
| { | ||
| (new DockerCompose())->exec( Control::SRV_CONTROL, 'bash' ); | ||
| return 0; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\Control; | ||
|
|
||
| use Addshore\Mwdd\DockerCompose\Control; | ||
| use Addshore\Mwdd\Shell\DockerCompose; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class Create extends Command | ||
| { | ||
|
|
||
| protected static $defaultName = 'ctrl:create'; | ||
|
|
||
| protected function configure() | ||
| { | ||
| $this->setDescription('Creates the control container (building if needed).'); | ||
| $this->setHidden(true); | ||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output) | ||
| { | ||
| (new DockerCompose())->upDetached( Control::SERVICES, $input->getOption('build')); | ||
| return 0; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\Control; | ||
|
|
||
| use Addshore\Mwdd\DockerCompose\Control; | ||
| use Addshore\Mwdd\Shell\DockerCompose; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class Suspend extends Command | ||
| { | ||
|
|
||
| protected static $defaultName = 'ctrl:suspend'; | ||
|
|
||
| protected function configure() | ||
| { | ||
| $this->setDescription('Suspends an already running control container.'); | ||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output) | ||
| { | ||
| (new DockerCompose())->stop(Control::SERVICES); | ||
| return 0; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\DockerCompose; | ||
|
|
||
| use Addshore\Mwdd\Shell\DockerCompose; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputArgument; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class Bash extends Command | ||
| { | ||
|
|
||
| protected static $defaultName = 'dc:bash'; | ||
|
|
||
| protected function configure() | ||
| { | ||
| $this->setDescription('Run a shell on one of the service containers'); | ||
| $this->addArgument( 'service' ); | ||
| $this->addArgument( 'shell', InputArgument::OPTIONAL, '', 'bash' ); | ||
|
|
||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output) | ||
| { | ||
| $service = $input->getArgument('service'); | ||
| $shell = $input->getArgument('shell'); | ||
|
|
||
| (new DockerCompose())->exec( $service, $shell ); | ||
| return 0; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\DockerCompose; | ||
|
|
||
| use Addshore\Mwdd\Shell\DockerCompose; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class Destroy extends Command | ||
| { | ||
|
|
||
| protected static $defaultName = 'dc:destroy'; | ||
|
|
||
| protected function configure() | ||
| { | ||
| $this->setDescription('Shut down all containers, and destroy them. Also deletes databases and volumes.'); | ||
| $this->setHelp('Shut down all containers, and destroy them. Also deletes databases and volumes.'); | ||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output) | ||
| { | ||
| $output->writeln("Containers and volumes are being destroyed."); | ||
| (new DockerCompose())->downWithVolumesAndOrphans(); | ||
|
|
||
| // This is not related to the destroy functionality, but this is nice to clean this up here... | ||
| if(file_exists(MWDD_DIR . '/.hosts')) { | ||
| unlink( MWDD_DIR . '/.hosts' ); | ||
| } | ||
| return 0; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\DockerCompose; | ||
|
|
||
| use Addshore\Mwdd\Shell\DockerCompose; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputArgument; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class Logs extends Command | ||
| { | ||
|
|
||
| protected static $defaultName = 'dc:logs'; | ||
|
|
||
| protected function configure() | ||
| { | ||
| $this->setDescription('Tails service logs.'); | ||
| $this->addArgument( 'service', InputArgument::REQUIRED ); | ||
| $this->addArgument( 'lines', null, '', 25 ); | ||
|
|
||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output) | ||
| { | ||
| $service = $input->getArgument('service'); | ||
| $lines = $input->getArgument('lines'); | ||
|
|
||
| (new DockerCompose())->logsTail( $service, $lines ); | ||
| return 0; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\DockerCompose; | ||
|
|
||
| use Addshore\Mwdd\Shell\DockerCompose; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class Ps extends Command | ||
| { | ||
|
|
||
| protected static $defaultName = 'dc:ps'; | ||
|
|
||
| protected function configure() | ||
| { | ||
| $this->setDescription('Runs docker-compose ps in the correct context.'); | ||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output) | ||
| { | ||
| (new DockerCompose())->ps(); | ||
| return 0; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\DockerCompose; | ||
|
|
||
| use Addshore\Mwdd\Shell\DockerCompose; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputArgument; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class Raw extends Command | ||
| { | ||
|
|
||
| protected static $defaultName = 'dc:raw'; | ||
|
|
||
| protected function configure() | ||
| { | ||
| $this->setDescription('Runs a command in the docker-compose context.'); | ||
| $this->setHelp( <<< EOT | ||
| Examples: | ||
| View the last 10 logs of the db-configure service: | ||
| dc:raw -- logs --tail=10 db-configure | ||
| EOT | ||
| ); | ||
| $this->addArgument('args', InputArgument::IS_ARRAY ); | ||
|
|
||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output) | ||
| { | ||
| $args = $input->getArgument('args'); | ||
|
|
||
| (new DockerCompose())->raw( implode( ' ', $args ) ); | ||
| return 0; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\MediaWiki; | ||
|
|
||
| use Addshore\Mwdd\DockerCompose\MwComposer; | ||
| use Addshore\Mwdd\Files\DotEnv; | ||
| use Addshore\Mwdd\Shell\DockerCompose; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputArgument; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class Composer extends Command | ||
| { | ||
|
|
||
| protected static $defaultName = 'mw:composer'; | ||
|
|
||
| protected function configure() | ||
| { | ||
| $this->setDescription('Runs composer for mediawiki or a subdirectory (when using the alias)'); | ||
| $this->setHelp( <<< EOT | ||
| Runs the composer command in a container within the MediaWiki context. | ||
| By default this will run in the MediaWiki core directory. | ||
| If you are using the recommended mwdd alias this command will try to run composer in the context of the directory you run the command from. | ||
| This is only relevant when said directory is within the mediawiki core directory. | ||
| Commands that rely on other applications, such as git, will NOT work as expected. | ||
| An example of this would be the Wikibase phpcs-modified script. | ||
| EOT | ||
| ); | ||
| $this->addUsage('version'); | ||
| $this->addUsage('update --ignore-platform-reqs'); | ||
|
|
||
| $this->addArgument('args', InputArgument::IS_ARRAY ); | ||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output) | ||
| { | ||
| // Try to run in the correct directory to run the command in | ||
| // TODO reuse this code somewhere.... | ||
| $shortcutEnv = getenv('MWDD_S_DIR'); | ||
| $pathInsideMwPath = ''; | ||
| if($shortcutEnv) { | ||
| $mwPath = (new DotEnv())->getValue('DOCKER_MW_PATH'); | ||
| // Trim /'s from the start and end, and ~ if used as the MW path base | ||
| $shortcutEnv = trim( $shortcutEnv, '/' ); | ||
| $mwPath = trim( $mwPath, '/~' ); | ||
| // Determine some stuff | ||
| $isInMwDir = strstr( $shortcutEnv, $mwPath ); | ||
| if($isInMwDir) { | ||
| $splitOnMwPath = explode( $mwPath, $shortcutEnv ); | ||
| $pathInsideMwPath = $splitOnMwPath[1]; | ||
| } | ||
| } | ||
|
|
||
| $args = $input->getArgument('args'); | ||
|
|
||
| // The service must be created in order to be able to use docker run | ||
| // TODO don't always run this... | ||
| $output->writeln("MWDD: Sorry that this is a bit slow to run (need to think of a nice fix) as it runs up each time"); | ||
| (new DockerCompose())->upDetached(MwComposer::SERVICES); | ||
|
|
||
| // TODO mount local .composer cache dir?! (done in getCode a bit already) | ||
| // User is specified in the docker-compose yml | ||
| (new DockerCompose())->run( | ||
| MwComposer::SRV_COMPOSER, | ||
| "composer " . implode( ' ', $args ), | ||
| '--rm --workdir=/app/' . $pathInsideMwPath | ||
| ); | ||
| return 0; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\MediaWiki; | ||
|
|
||
| use Addshore\Mwdd\DockerCompose\MwComposer; | ||
| use Addshore\Mwdd\DockerCompose\MwFresh; | ||
| use Addshore\Mwdd\Files\DotEnv; | ||
| use Addshore\Mwdd\Shell\DockerCompose; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputArgument; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class Fresh extends Command | ||
| { | ||
|
|
||
| protected static $defaultName = 'mw:fresh'; | ||
|
|
||
| protected function configure() | ||
| { | ||
| $this->setDescription('Runs fresh for MediaWiki or a subdirectory (when using the alias)'); | ||
| $this->addUsage('npm install'); | ||
| $this->addUsage('npm run selenium'); | ||
| $this->setHelp( <<< EOT | ||
| Runs 'fresh', a node js running environment, within the MediaWiki context. | ||
| See: https://github.com/wikimedia/fresh | ||
| By default this will run in the MediaWiki core directory. | ||
| If you are using the recommended mwdd alias this command will try to run composer in the context of the directory you run the command from. | ||
| This is only relevant when said directory is within the mediawiki core directory. | ||
| EOT | ||
| ); | ||
|
|
||
| $this->addArgument('args', InputArgument::IS_ARRAY ); | ||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output) | ||
| { | ||
| // Try to run in the correct directory to run the command in | ||
| // TODO reuse this code somewhere.... | ||
| $shortcutEnv = getenv('MWDD_S_DIR'); | ||
| $pathInsideMwPath = ''; | ||
| if($shortcutEnv) { | ||
| $mwPath = (new DotEnv())->getValue('DOCKER_MW_PATH'); | ||
| // Trim /'s from the start and end, and ~ if used as the MW path base | ||
| $shortcutEnv = trim( $shortcutEnv, '/' ); | ||
| $mwPath = trim( $mwPath, '/~' ); | ||
| // Determine some stuff | ||
| $isInMwDir = strstr( $shortcutEnv, $mwPath ); | ||
| if($isInMwDir) { | ||
| $splitOnMwPath = explode( $mwPath, $shortcutEnv ); | ||
| $pathInsideMwPath = $splitOnMwPath[1]; | ||
| } | ||
| } | ||
|
|
||
| $args = $input->getArgument('args'); | ||
|
|
||
| // The service must be created in order to be able to use docker run | ||
| // TODO don't always run this... | ||
| $output->writeln("MWDD: Sorry that this is a bit slow to run (need to think of a nice fix) as it runs up each time"); | ||
| $output->writeln("MWDD: Fresh also seems to be a bit buggy currently and sometimes freeze? maybe?"); | ||
| (new DockerCompose())->upDetached(MwFresh::SERVICES); | ||
|
|
||
|
|
||
| // TODO needs addslashes a little for " ? | ||
| if(strstr(implode( ' ', $args ), '"')) { | ||
| $output->writeln('MWDD: WARNING, Your arguments have a " in them, I currently predict something will go wrong.'); | ||
| } | ||
|
|
||
| // User is specified in the docker-compose yml | ||
| (new DockerCompose())->run( | ||
| MwFresh::SRV_FRESH, | ||
| // TODO needs addslashes a little for " ? | ||
| '-c "' . implode( ' ', $args ) . '"', | ||
| '--rm --workdir=/app/' . $pathInsideMwPath | ||
| ); | ||
| return 0; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\Mediawiki; | ||
|
|
||
| use Addshore\Mwdd\Files\DotEnv; | ||
| use Addshore\Mwdd\Files\MediaWikiDir; | ||
| use Addshore\Mwdd\Shell\Docker; | ||
| use Addshore\Mwdd\Shell\Git; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
| use Symfony\Component\Console\Question\ConfirmationQuestion; | ||
|
|
||
| class GetCode extends Command { | ||
|
|
||
| protected static $defaultName = 'mw:getcode'; | ||
|
|
||
| protected function configure() { | ||
| $this->setDescription('Gets MediaWiki code if you don\'t already have it.'); | ||
| // TODO right now this doesnt auto gen the file if it already exists... so just always show the command, maybe we need a different config? :D | ||
| $this->setHidden((new MediaWikiDir((new DotEnv(true))->getValue('DOCKER_MW_PATH')))->hasDotGitDirectory()); | ||
| } | ||
|
|
||
| protected function execute( InputInterface $input, OutputInterface $output ) { | ||
| $mwPath = (new DotEnv())->getValue('DOCKER_MW_PATH'); | ||
|
|
||
| $output->writeln("Your currently configured MediaWiki path is: " . $mwPath); | ||
| $helper = $this->getHelper('question'); | ||
| $question = new ConfirmationQuestion('Would you like to fetch code there??', false); | ||
|
|
||
| if (!$helper->ask($input, $output, $question)) { | ||
| $output->writeln("Please update your local.env before continuing."); | ||
| return 0; | ||
| } | ||
|
|
||
| $mwDir = new MediaWikiDir( $mwPath ); | ||
|
|
||
| // Clone the minimum needed code | ||
| ( new Git() )->clone( 'https://gerrit.wikimedia.org/r/mediawiki/core', $mwDir ); | ||
| ( new Git() )->clone( 'https://gerrit.wikimedia.org/r/mediawiki/skins/Vector', | ||
| $mwDir | ||
| . '/skins/Vector' ); | ||
|
|
||
| // Run composer install (not as part of compose) | ||
| ( new Docker() )->runComposerInstall( $mwDir ); | ||
|
|
||
| // Create the basic local settings file... | ||
| $lsFile = $mwDir . '/LocalSettings.php'; | ||
| $initialLocalSettings = <<<EOT | ||
| <?php | ||
| require_once '/mwdd-custom/LocalSettings.php'; | ||
| wfLoadSkin( 'Vector' ); | ||
| EOT; | ||
| file_put_contents( $lsFile, $initialLocalSettings ); | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\Mediawiki; | ||
|
|
||
| use Addshore\Mwdd\Command\TraitForCommandsThatAddHosts; | ||
| use Addshore\Mwdd\DockerCompose\Base; | ||
| use Addshore\Mwdd\Shell\DockerCompose; | ||
| use Addshore\Mwdd\Shell\Id; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputArgument; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class Install extends Command | ||
| { | ||
|
|
||
| use TraitForCommandsThatAddHosts; | ||
|
|
||
| protected static $defaultName = 'mw:install'; | ||
|
|
||
| protected function configure() | ||
| { | ||
| $this->setDescription('Installs a new MediaWiki site.'); | ||
| $this->setHelp(<<<EOH | ||
| This command does the following: | ||
| 1) Creates some directories in the container for images, tmp storage and caching (777 permissions). | ||
| - /app/images/docker/<sitename> | ||
| - /app/images/docker/<sitename>/tmp | ||
| - /app/images/docker/<sitename>/cache | ||
| 2) Runs the installdbs shell script which: | ||
| - Waits for db-master service to be ready | ||
| - Moves the user LocalSettings.php file out of the way | ||
| - Runs install.php | ||
| - Moves the user LocalSettings.php back | ||
| - Runs update.php | ||
| EOH | ||
| ); | ||
|
|
||
| $this->addArgument( 'site', InputArgument::OPTIONAL, 'The site name to install', 'default' ); | ||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output) | ||
| { | ||
| $site = $input->getArgument( 'site' ); | ||
| $output->writeln("Adding new site: " . $site); | ||
|
|
||
| // Make some directories that ONLY exist within the container (anon volume) | ||
| // TODO could chown the dirs to someone else? | ||
| (new DockerCompose())->exec( Base::SRV_MEDIAWIKI, 'mkdir -m 777 -p //app/images/docker/' . $site ); | ||
| (new DockerCompose())->exec( Base::SRV_MEDIAWIKI, 'mkdir -m 777 -p //app/images/docker/' . $site . '/tmp' ); | ||
| (new DockerCompose())->exec( Base::SRV_MEDIAWIKI, 'mkdir -m 777 -p //app/images/docker/' . $site . '/cache' ); | ||
|
|
||
| $ug = (new Id())->ug(); | ||
| // TODO try to output these commands as they are running to the user for observability..? | ||
| (new DockerCompose())->exec( Base::SRV_MEDIAWIKI, 'bash //mwdd-custom/installdbs ' . $site, "--user ${ug}" ); | ||
|
|
||
| $this->addHostsAndPrintOutput( [ $site . '.web.mw.localhost' ], $output ); | ||
| return 0; | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\Mediawiki; | ||
|
|
||
| use Addshore\Mwdd\DockerCompose\Base; | ||
| use Addshore\Mwdd\Shell\DockerCompose; | ||
| use Addshore\Mwdd\Shell\Id; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputArgument; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Input\InputOption; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class Maint extends Command | ||
| { | ||
|
|
||
| protected static $defaultName = 'mw:maint'; | ||
|
|
||
| protected function configure() | ||
| { | ||
| $this->setDescription('Runs a MediaWiki maintenance script'); | ||
|
|
||
| $this->addArgument('script', InputArgument::REQUIRED | InputArgument::IS_ARRAY ); | ||
| $this->addOption('wiki', null, InputArgument::OPTIONAL, '', 'default' ); | ||
| $this->addOption('debug', 'd', InputOption::VALUE_OPTIONAL, 'Enable debugger'); | ||
| $this->ignoreValidationErrors(); | ||
|
|
||
| $this->addUsage('-- maintenance/showJobs.php'); | ||
| $this->addUsage('-- maintenance/showJobs.php --group'); | ||
| $this->addUsage('--wiki=other -- maintenance/showJobs.php'); | ||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output) | ||
| { | ||
| $debugPrefix = ''; | ||
| if($input->getOption('debug')) { | ||
| $debugPrefix = 'XDEBUG_CONFIG=\"remote_host=${XDEBUG_REMOTE_HOST}\" '; | ||
| } | ||
|
|
||
| $wiki = $input->getOption('wiki'); | ||
| $script = implode( ' ', $input->getArgument('script') ); | ||
|
|
||
| $ug = (new Id())->ug(); | ||
| // exec instead of run so that we don't load the depends ons..... (but we could state not to load them?) | ||
| (new DockerCompose())->exec( | ||
| Base::SRV_MEDIAWIKI, | ||
| "sh -c \"${debugPrefix}php //app/${script} --wiki ${wiki}\"", | ||
| "--user ${ug}" | ||
| ); | ||
| return 0; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\MediaWiki; | ||
|
|
||
| use Addshore\Mwdd\DockerCompose\Base; | ||
| use Addshore\Mwdd\Shell\DockerCompose; | ||
| use Addshore\Mwdd\Shell\Id; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Input\InputOption; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class PHPUnit extends Command | ||
| { | ||
|
|
||
| protected static $defaultName = 'mw:phpunit'; | ||
|
|
||
| protected function configure() | ||
| { | ||
| $this->setDescription('Runs the MediaWiki phpunit.php'); | ||
|
|
||
| $this->addArgument('testPath', InputOption::VALUE_REQUIRED ); | ||
| $this->addOption('wiki', 'w', InputOption::VALUE_OPTIONAL, 'The wiki to run the tests for', 'default'); | ||
| $this->addOption('args', 'a', InputOption::VALUE_OPTIONAL, 'String of extra arguments to pass to phpunit.php', ''); | ||
| $this->addOption('debug', 'd', InputOption::VALUE_OPTIONAL, 'Enable debugger'); | ||
|
|
||
| $this->addUsage('tests/phpunit/includes/StatusTest.php'); | ||
| $this->addUsage('-d=1 tests/phpunit/includes/StatusTest.php'); | ||
| $this->addUsage('tests/phpunit/includes/StatusTest.php --wiki otherwiki'); | ||
| $this->addUsage('extensions/Wikibase/lib/tests/phpunit/Store/Sql/TermSqlIndexTest.php'); | ||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output) | ||
| { | ||
| $path = $input->getArgument('testPath'); | ||
| if(empty($path)) { | ||
| $output->writeln("path must be specified"); | ||
| return 1; | ||
| } | ||
| $wiki = $input->getOption('wiki'); | ||
| $args = $input->getOption('args'); | ||
| $debugPrefix = ''; | ||
| if($input->getOption('debug')) { | ||
| $debugPrefix = 'XDEBUG_CONFIG=\"remote_host=${XDEBUG_REMOTE_HOST}\" '; | ||
| } | ||
|
|
||
| $ug = (new Id())->ug(); | ||
| // This runs in the mediawiki service currently, but we could consider running it as a tool (similar to fresh etc) | ||
| // exec instead of run so that we don't load the depends ons..... (but we could state not to load them?) | ||
| (new DockerCompose())->exec( | ||
| Base::SRV_MEDIAWIKI, | ||
| "sh -c \"${debugPrefix}php //app/tests/phpunit/phpunit.php ${args} --wiki ${wiki} //app/${path}\"", | ||
| "--user ${ug}" | ||
| ); | ||
| return 0; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\MediaWiki; | ||
|
|
||
| use Addshore\Mwdd\DockerCompose\MwComposer; | ||
| use Addshore\Mwdd\DockerCompose\MwFresh; | ||
| use Addshore\Mwdd\DockerCompose\MwQuibble; | ||
| use Addshore\Mwdd\Files\DotEnv; | ||
| use Addshore\Mwdd\Shell\DockerCompose; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputArgument; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class Quibble extends Command | ||
| { | ||
|
|
||
| protected static $defaultName = 'mw:quibble'; | ||
|
|
||
| protected function configure() | ||
| { | ||
| $this->addArgument('args', InputArgument::IS_ARRAY ); | ||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output) | ||
| { | ||
| // Try to run in the correct directory to run the command in | ||
| // TODO reuse this code somewhere.... | ||
| // $shortcutEnv = getenv('MWDD_S_DIR'); | ||
| $pathInsideMwPath = ''; | ||
| // if($shortcutEnv) { | ||
| // $mwPath = (new DotEnv())->getValue('DOCKER_MW_PATH'); | ||
| // // Trim /'s from the start and end, and ~ if used as the MW path base | ||
| // $shortcutEnv = trim( $shortcutEnv, '/' ); | ||
| // $mwPath = trim( $mwPath, '/~' ); | ||
| // // Determine some stuff | ||
| // $isInMwDir = strstr( $shortcutEnv, $mwPath ); | ||
| // if($isInMwDir) { | ||
| // $splitOnMwPath = explode( $mwPath, $shortcutEnv ); | ||
| // $pathInsideMwPath = $splitOnMwPath[1]; | ||
| // } | ||
| // } | ||
|
|
||
| $args = $input->getArgument('args'); | ||
|
|
||
| // The service must be created in order to be able to use docker run | ||
| // TODO don't always run this... | ||
| $output->writeln("MWDD: Sorry that this is a bit slow to run (need to think of a nice fix) as it runs up each time"); | ||
| $output->writeln("MWDD: Quibble also han't been tested at all"); | ||
| (new DockerCompose())->upDetached(MwQuibble::SERVICES); | ||
|
|
||
|
|
||
| // TODO needs addslashes a little for " ? | ||
| if(strstr(implode( ' ', $args ), '"')) { | ||
| $output->writeln('MWDD: WARNING, Your arguments have a " in them, I currently predict something will go wrong.'); | ||
| } | ||
|
|
||
| (new DockerCompose())->run( | ||
| MwQuibble::SRV_QUIBBLE, | ||
| " --skip-zuul --skip-deps --skip-install " . implode( ' ', $args ), | ||
| '--rm --entrypoint=/usr/local/bin/quibble --workdir=/app/' . $pathInsideMwPath | ||
| ); | ||
| return 0; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\ServiceBase; | ||
|
|
||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\ArrayInput; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class Cli extends Command | ||
| { | ||
|
|
||
| protected $serviceSetName; | ||
| protected $cliTool; | ||
| protected $help; | ||
|
|
||
| public function __construct( string $serviceSetName, string $cliTool, string $help ) { | ||
| $this->serviceSetName = $serviceSetName; | ||
| $this->cliTool = $cliTool; | ||
| $this->help = $help; | ||
| parent::__construct(); | ||
| } | ||
|
|
||
| protected function configure() { | ||
| $this->setName($this->serviceSetName . ':cli'); | ||
| $this->setHelp( | ||
| $this->help . PHP_EOL . PHP_EOL . | ||
| 'This command uses <info>docker-compose exec</info> internally.' | ||
| ); | ||
| $this->setDescription('Runs the cli tool for this service in a container' ); | ||
|
|
||
| $this->addUsage(''); | ||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output) | ||
| { | ||
| return $this->getApplication()->find($this->serviceSetName . ':exec')->run( new ArrayInput([ Exec::COMMAND => $this->cliTool ]), $output ); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\ServiceBase; | ||
|
|
||
| use Addshore\Mwdd\Command\TraitForCommandsThatAddHosts; | ||
| use Addshore\Mwdd\DockerCompose\ServiceSet; | ||
| use Addshore\Mwdd\Files\DotEnv; | ||
| use Addshore\Mwdd\Shell\DockerCompose; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class Create extends Command | ||
| { | ||
|
|
||
| use TraitForCommandsThatAddHosts; | ||
|
|
||
| protected $serviceSetName; | ||
| protected $help; | ||
|
|
||
| public function __construct( string $serviceSetName, string $help ) { | ||
| $this->serviceSetName = $serviceSetName; | ||
| $this->help = $help; | ||
| parent::__construct(); | ||
| } | ||
|
|
||
| protected function configure() { | ||
| $this->setName($this->serviceSetName . ':create' ); | ||
| $this->setHelp( | ||
| $this->help . PHP_EOL . PHP_EOL . | ||
| 'This command uses <info>docker-compose up -d</info> internally.' | ||
| ); | ||
| $this->setDescription('Creates or recreates the service containers' ); | ||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output) | ||
| { | ||
| $serviceSet = new ServiceSet($this->serviceSetName); | ||
| $dotEnv = new DotEnv(); | ||
| $dotEnv->updateFromDefaultAndLocal(); | ||
|
|
||
| // Output which services we will be running | ||
| $serviceNames = $serviceSet->getServiceNames(); | ||
| $output->writeln('Starting services (with deps): ' . implode( ',', $serviceNames )); | ||
| // TODO output what docker-composer command is being run? (slim version) | ||
| (new DockerCompose())->upDetached( $serviceNames ); | ||
|
|
||
| $this->addHostsAndPrintOutput( $serviceSet->getVirtualHosts(), $output ); | ||
| return 1; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\ServiceBase; | ||
|
|
||
| use Addshore\Mwdd\DockerCompose\ServiceSet; | ||
| use Addshore\Mwdd\Shell\DockerCompose; | ||
| use Addshore\Mwdd\Shell\Id; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Input\InputOption; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class Exec extends Command | ||
| { | ||
|
|
||
| public const COMMAND = 'COMMAND'; | ||
| public const SERVICE = 'SERVICE'; | ||
| public const USER = 'user'; | ||
|
|
||
| protected $serviceSetName; | ||
| protected $help; | ||
|
|
||
| protected const DEFAULT_COMMAND = 'Auto detect shell (sh/bash)'; | ||
| protected const DEFAULT_SERVICE = 'Primary / first service'; | ||
| protected const DEFAULT_USER = 'Host machine user'; | ||
|
|
||
| public function __construct( string $serviceSetName, string $help ) { | ||
| $this->serviceSetName = $serviceSetName; | ||
| $this->help = $help; | ||
| parent::__construct(); | ||
| } | ||
|
|
||
| protected function configure() { | ||
| $this->setName($this->serviceSetName . ':exec'); | ||
| $this->setHelp( | ||
| $this->help . PHP_EOL . PHP_EOL . | ||
| 'This command uses <info>docker-compose exec</info> internally.' | ||
| ); | ||
| $this->setDescription('Runs a command a running service container' ); | ||
|
|
||
| $this->addArgument( | ||
| self::COMMAND, | ||
| null, | ||
| 'Which COMMAND to run inside the container.', | ||
| self::DEFAULT_COMMAND | ||
| ); | ||
| $this->addArgument( | ||
| self::SERVICE, | ||
| null, | ||
| 'Which container to run the COMMAND inside of? Defaults to the primary service.', | ||
| self::DEFAULT_SERVICE | ||
| ); | ||
|
|
||
| $this->addOption( | ||
| self::USER, | ||
| null, | ||
| InputOption::VALUE_OPTIONAL, | ||
| 'Which user to run as', | ||
| self::DEFAULT_USER | ||
| ); | ||
|
|
||
| $this->addUsage(''); | ||
| $this->addUsage('bash'); | ||
| $this->addUsage('--user=root bash'); | ||
| $this->addUsage('sh'); | ||
| $this->addUsage('sh other-service'); | ||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output) | ||
| { | ||
| $serviceSet = new ServiceSet($this->serviceSetName); | ||
|
|
||
| $command = $input->getArgument( self::COMMAND ); | ||
| if($command === self::DEFAULT_COMMAND) { | ||
| // use sh which we probably have to detect if bash is there and use the best one | ||
| $command = 'sh -c "if [ $(command -v bash) ]; then bash; else sh; fi"'; | ||
| } | ||
|
|
||
| $service = $input->getArgument( self::SERVICE ); | ||
| if($service === self::DEFAULT_SERVICE) { | ||
| // Get the first service listed in the docker-compose yml which should be the most important | ||
| $service = $serviceSet->getServiceNames()[0]; | ||
| } | ||
|
|
||
| $user = $input->getOption( self::USER ); | ||
| if($user === self::DEFAULT_USER) { | ||
| $output->writeln('MWDD: You may see a message saying the user or group ID doesnt exist, but you can ignore it'); | ||
| $user = (new Id())->ug(); | ||
| } | ||
|
|
||
| (new DockerCompose())->execIt( $service, $command, '--user ' . $user ); | ||
|
|
||
| return 0; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\ServiceBase; | ||
|
|
||
| use Addshore\Mwdd\DockerCompose\ServiceSet; | ||
| use Addshore\Mwdd\Shell\DockerCompose; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputArgument; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class Logs extends Command | ||
| { | ||
|
|
||
| private const LOG_DEFAULT_LS = 'Lists available log files'; | ||
|
|
||
| protected $serviceSetName; | ||
| protected $help; | ||
|
|
||
| public function __construct( string $serviceSetName, string $help ) { | ||
| $this->serviceSetName = $serviceSetName; | ||
| $this->help = $help; | ||
| parent::__construct(); | ||
| } | ||
|
|
||
| protected function configure() | ||
| { | ||
| $serviceSet = new ServiceSet($this->serviceSetName); | ||
|
|
||
| $logDir = $serviceSet->getEnvVarForFirstService('MWDD_LOG_DIR' ); | ||
| // Don't show the command if the service doesnt have a log dir configured.. | ||
| $this->setHidden(!$logDir); | ||
|
|
||
| /** | ||
| * In order to output more logs to this directory you might have to enable extra log groups. | ||
| https://www.mediawiki.org/wiki/Manual:\$wgDebugLogGroups | ||
| \$wgDebugLogGroups['debug'] = "/var/log/mediawiki/debug.log"; | ||
| \$wgDebugLogGroups['Wikibase'] = "/var/log/mediawiki/wikibase.log"; | ||
| */ | ||
|
|
||
| $this->setName($this->serviceSetName . ':logs'); | ||
| $this->setHelp( | ||
| $this->help . PHP_EOL . PHP_EOL . | ||
| 'This command uses <info>docker-compose exec</info> internally to run <info>tail -f</info> in the container.' | ||
| ); | ||
| $this->setDescription('Tail service logs' ); | ||
|
|
||
| $this->addArgument('log', InputArgument::OPTIONAL, '', self::LOG_DEFAULT_LS ); | ||
|
|
||
| $this->addUsage(''); | ||
| $this->addUsage('debug.log'); | ||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output) | ||
| { | ||
| $serviceSet = new ServiceSet($this->serviceSetName); | ||
|
|
||
| $log = $input->getArgument('log'); | ||
|
|
||
| if( $log === self::LOG_DEFAULT_LS ) { | ||
| $output->writeln('Listing available log files:'); | ||
| (new DockerCompose())->exec( $serviceSet->getFirstServiceName(), "ls /var/log/mediawiki/"); | ||
| } else { | ||
| (new DockerCompose())->exec( $serviceSet->getFirstServiceName(), "tail -f /var/log/mediawiki/${log}"); | ||
| } | ||
|
|
||
| return 0; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\ServiceBase; | ||
|
|
||
| use Addshore\Mwdd\DockerCompose\ServiceSet; | ||
| use Addshore\Mwdd\Shell\DockerCompose; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class Resume extends Command | ||
| { | ||
|
|
||
| protected $serviceSetName; | ||
| protected $help; | ||
|
|
||
| public function __construct( string $serviceSetName, string $help ) { | ||
| $this->serviceSetName = $serviceSetName; | ||
| $this->help = $help; | ||
| parent::__construct(); | ||
| } | ||
|
|
||
| protected function configure() { | ||
| $this->setName($this->serviceSetName . ':resume'); | ||
| $this->setHelp( | ||
| $this->help . PHP_EOL . PHP_EOL . | ||
| 'This command uses <info>docker-compose start</info> internally.' | ||
| ); | ||
| $this->setDescription('Resumes a set of previously created containers' ); | ||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output) | ||
| { | ||
| $serviceSet = new ServiceSet($this->serviceSetName); | ||
| (new DockerCompose())->start( $serviceSet->getServiceNames()); | ||
| return 0; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command\ServiceBase; | ||
|
|
||
| use Addshore\Mwdd\DockerCompose\ServiceSet; | ||
| use Addshore\Mwdd\Shell\DockerCompose; | ||
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class Suspend extends Command | ||
| { | ||
|
|
||
| protected $serviceSetName; | ||
| protected $help; | ||
|
|
||
| public function __construct( string $serviceSetName, string $help ) { | ||
| $this->serviceSetName = $serviceSetName; | ||
| $this->help = $help; | ||
| parent::__construct(); | ||
| } | ||
|
|
||
| protected function configure() { | ||
| $this->setName($this->serviceSetName . ':suspend'); | ||
| $this->setHelp( | ||
| $this->help . PHP_EOL . PHP_EOL . | ||
| 'This command uses <info>docker-compose stop</info> internally.' | ||
| ); | ||
| $this->setDescription('Suspends a set of previously created containers' ); | ||
|
|
||
| } | ||
|
|
||
| protected function execute(InputInterface $input, OutputInterface $output) | ||
| { | ||
| $serviceSet = new ServiceSet($this->serviceSetName); | ||
| (new DockerCompose())->stop( $serviceSet->getServiceNames()); | ||
| return 0; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Command; | ||
|
|
||
| use Addshore\Mwdd\Files\DotEnv; | ||
| use Symfony\Component\Console\Input\ArrayInput; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| trait TraitForCommandsThatAddHosts { | ||
|
|
||
| private $addedHosts = []; | ||
|
|
||
| protected function addHostsAndPrintOutput( array $hosts, OutputInterface $output ) : void{ | ||
| foreach( $hosts as $host ) { | ||
| $this->addHost( $host, $output ); | ||
| } | ||
| $this->printInfoAboutAddedHosts( $output ); | ||
| } | ||
|
|
||
| protected function addHosts( array $hosts, OutputInterface $output ) : void{ | ||
| foreach( $hosts as $host ) { | ||
| $this->addHost( $host, $output ); | ||
| } | ||
| } | ||
|
|
||
| protected function addHost( string $host, OutputInterface $output ) :void { | ||
| $this->getApplication()->find('base:hosts-add')->run( new ArrayInput([ 'host' => $host ]), $output ); | ||
| $this->addedHosts[] = $host; | ||
| } | ||
|
|
||
| protected function printInfoAboutAddedHosts( OutputInterface $output ): void { | ||
| if( !$this->addedHosts ) { | ||
| return; | ||
| } | ||
|
|
||
| $dotEnv = new DotEnv(); | ||
| $dotEnv->updateFromDefaultAndLocal(); | ||
| $publicPort = $dotEnv->getValue('DOCKER_MW_PORT'); | ||
|
|
||
| $output->writeln('Some processes added new host (accessible via HTTP):'); | ||
| foreach( $this->addedHosts as $host ) { | ||
| $output->writeln( " - <href=http://${host}:${publicPort}>http://${host}:${publicPort}</>"); | ||
| } | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\DockerCompose; | ||
|
|
||
| class Base { | ||
|
|
||
| public const SRV_MEDIAWIKI = 'mediawiki'; | ||
| public const SRV_DPS = 'dps'; | ||
| public const SRV_DB_MASTER = 'db-master'; | ||
| public const SRV_DB_CONFIGURE = 'db-configure'; | ||
| public const SRV_NGINX_PROXY = 'nginx-proxy'; | ||
|
|
||
| public const SERVICES = [ | ||
| self::SRV_DPS, | ||
| self::SRV_DB_MASTER, | ||
| self::SRV_DB_CONFIGURE, | ||
| self::SRV_NGINX_PROXY, | ||
| self::SRV_MEDIAWIKI, | ||
| ]; | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\DockerCompose; | ||
|
|
||
| class Control { | ||
|
|
||
| public const SRV_CONTROL = 'control'; | ||
|
|
||
| public const SERVICES = [ | ||
| self::SRV_CONTROL, | ||
| ]; | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\DockerCompose; | ||
|
|
||
| class MwComposer { | ||
|
|
||
| public const SRV_COMPOSER = 'mw-composer'; | ||
|
|
||
| public const SERVICES = [ | ||
| self::SRV_COMPOSER, | ||
| ]; | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\DockerCompose; | ||
|
|
||
| class MwFresh { | ||
|
|
||
| public const SRV_FRESH = 'mw-fresh'; | ||
|
|
||
| public const SERVICES = [ | ||
| self::SRV_FRESH, | ||
| ]; | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\DockerCompose; | ||
|
|
||
| class MwQuibble { | ||
|
|
||
| public const SRV_QUIBBLE = 'mw-quibble'; | ||
|
|
||
| public const SERVICES = [ | ||
| self::SRV_QUIBBLE, | ||
| ]; | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\DockerCompose; | ||
|
|
||
| use Addshore\Mwdd\Files\DotEnv; | ||
| use M1\Env\Parser; | ||
| use Symfony\Component\Yaml\Yaml; | ||
|
|
||
| /** | ||
| * A service set represents a docker-compose.yml file with a set of services within it. | ||
| * These services should be designed to fit into the mwdd espectations, which means: | ||
| * - dns configured? | ||
| * - VHOST exposed if desired? | ||
| * - matching docker-compose version.... | ||
| */ | ||
| class ServiceSet { | ||
|
|
||
| /** | ||
| * @var string | ||
| */ | ||
| private $dcName; | ||
|
|
||
| /** | ||
| * @var array|null | ||
| */ | ||
| private $yaml; | ||
|
|
||
| /** | ||
| * @param string $dcName Name of the dc file, without path or extension | ||
| */ | ||
| public function __construct( string $dcName ) { | ||
| $this->dcName = $dcName; | ||
| } | ||
|
|
||
| private function getYaml() { | ||
| if(!$this->yaml) { | ||
| $this->yaml = Yaml::parseFile(__DIR__ . '/../../../docker-compose/' . $this->dcName . '.yml'); | ||
| // TODO validate against expectations once loaded? | ||
| } | ||
| return $this->yaml; | ||
| } | ||
|
|
||
| private function getServices() { | ||
| return $this->getYaml()['services']; | ||
| } | ||
|
|
||
| private function getService( string $name ) { | ||
| return $this->getServices()[$name]; | ||
| } | ||
|
|
||
| public function getFirstServiceName() { | ||
| return array_keys($this->getServices())[0]; | ||
| } | ||
|
|
||
| public function getServiceNames() { | ||
| return array_keys($this->getServices()); | ||
| } | ||
|
|
||
| private function getParsedEquivEnvFile( string $serviceName ) { | ||
| $service = $this->getService( $serviceName ); | ||
|
|
||
| // Bail early if there are no environment values | ||
| if(!array_key_exists('environment', $service)) { | ||
| return new Parser(''); | ||
| } | ||
|
|
||
| // Replace values from .env that need it | ||
| $dotEnv = (new DotEnv()); | ||
| $dotEnv->updateFromDefaultAndLocal(); | ||
| $cleanedEnvData = []; | ||
| foreach( $service['environment'] as $envLine ) { | ||
| preg_match_all( '/\$\{([^\}]*)\}/', $envLine, $matches ); | ||
| foreach($matches[0] as $matchKey => $match) { | ||
| $matchesEnvKey = $matches[1][$matchKey]; | ||
| $envLine = str_replace( $match, $dotEnv->getValue($matchesEnvKey), $envLine ); | ||
| } | ||
| // XXX EVIL SUPER EVIL HACK | ||
| $envLine = str_replace( 'php.apc.enable_cli', 'php_apc_enable_cli', $envLine ); | ||
| $cleanedEnvData[] = $envLine; | ||
| } | ||
|
|
||
| return new Parser(implode(PHP_EOL, $cleanedEnvData)); | ||
| } | ||
|
|
||
| public function getEnvVar( string $serviceName, string $envVarName ) { | ||
| $environment = $this->getParsedEquivEnvFile( $serviceName ); | ||
| return $environment->getContent( $envVarName ); | ||
| } | ||
|
|
||
| public function getEnvVarForFirstService( string $envVarName ) { | ||
| return $this->getEnvVar( $this->getFirstServiceName(), $envVarName ); | ||
| } | ||
|
|
||
| public function getVirtualHosts() { | ||
| $hosts = []; | ||
| foreach($this->getServiceNames() as $servicesName ) { | ||
| $host = $this->getEnvVar( $servicesName, 'VIRTUAL_HOST' ); | ||
| if($host) { | ||
| $hosts[] = $host; | ||
| } | ||
| } | ||
| return $hosts; | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Files; | ||
|
|
||
| use M1\Env\Parser; | ||
|
|
||
| class DotEnv { | ||
|
|
||
| private const FILE = MWDD_DIR . '/.env'; | ||
| private const DEFAULT = MWDD_DIR . '/default.env'; | ||
| private const LOCAL = MWDD_DIR . '/local.env'; | ||
|
|
||
| private $forceFresh; | ||
|
|
||
| public function __construct( bool $forceFresh = false ) { | ||
| $this->forceFresh = $forceFresh; | ||
| } | ||
|
|
||
| private function useForceFreshFlag() { | ||
| if( $this->forceFresh ){ | ||
| // Avoid keeping on getting fresh .env file | ||
| $this->forceFresh = false; | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| public function exists() : bool { | ||
| return file_exists(self::FILE); | ||
| } | ||
|
|
||
| public function getValue(string $key) : ?string { | ||
| if($this->useForceFreshFlag() || !$this->exists()) { | ||
| $this->updateFromDefaultAndLocal(); | ||
| } | ||
| $dotEnv = (new Parser(file_get_contents(self::FILE))); | ||
| return $dotEnv->getContent($key); | ||
| } | ||
|
|
||
| /** | ||
| * Combines the default.env and local.env files for the environment into a single .env file | ||
| */ | ||
| public function updateFromDefaultAndLocal() { | ||
| $defaultEnv = (new Parser(file_get_contents(self::DEFAULT))); | ||
|
|
||
| // Sometimes users will not have specified a local env file just yet... | ||
| if(file_exists(self::LOCAL)) { | ||
| $localEnv = (new Parser(file_get_contents(self::LOCAL))); | ||
| $finalEnvLines = array_merge( | ||
| $defaultEnv->lines, | ||
| $localEnv->lines | ||
| ); | ||
| } else { | ||
| $finalEnvLines = $defaultEnv->lines; | ||
| } | ||
|
|
||
| $finalEnvLines = $this->swapOutValues( $finalEnvLines ); | ||
|
|
||
| $finalLines = ''; | ||
| foreach( $finalEnvLines as $key => $line ) { | ||
| $finalLines .= $key . '=' . "${line}" . PHP_EOL; | ||
| } | ||
|
|
||
| file_put_contents( self::FILE, $finalLines ); | ||
| } | ||
|
|
||
| private function swapOutValues( array $combinesLines ) { | ||
| if($combinesLines['UID'] === '{{id -u}}'){ | ||
| $combinesLines['UID'] = trim(shell_exec('id -u')); | ||
| } | ||
| if($combinesLines['GID'] === '{{id -g}}'){ | ||
| $combinesLines['GID'] = trim(shell_exec('id -g')); | ||
| } | ||
| return $combinesLines; | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Files; | ||
|
|
||
| class DotHosts { | ||
|
|
||
| private const FILE = MWDD_DIR . '/.hosts'; | ||
| private const SUFFIX = "# mediawiki-docker-dev"; | ||
|
|
||
| public function addHost( string $ip, string $host ) { | ||
| $this->addLine( "${ip} ${host} " . self::SUFFIX ); | ||
| } | ||
|
|
||
| private function ensureFileExists() { | ||
| touch(self::FILE); | ||
| } | ||
|
|
||
| private function addLine( string $line ) { | ||
| $this->ensureFileExists(); | ||
| file_put_contents(self::FILE, trim($line).PHP_EOL , FILE_APPEND | LOCK_EX); | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Files; | ||
|
|
||
| class MediaWikiDir { | ||
|
|
||
| private $dir; | ||
|
|
||
| /** | ||
| * Passed through realpath on the host | ||
| */ | ||
| private $realPath; | ||
|
|
||
| public function __construct( string $dir) { | ||
| $this->dir = $dir; | ||
| } | ||
|
|
||
| public function ensurePresent() { | ||
| // Ignore errors...... | ||
| // Maybe we want to show errors though? | ||
| //@mkdir($this->dir, 0777, true); | ||
| passthru('mkdir -p ' . $this->dir); | ||
| } | ||
|
|
||
| private function getRealPath() { | ||
| if(!$this->realPath) { | ||
| $this->ensurePresent(); | ||
| $dir = trim(shell_exec('realpath ' . $this->dir)); | ||
| $this->realPath = $dir; | ||
| } | ||
| return $this->realPath; | ||
| } | ||
|
|
||
| public function hasDotGitDirectory() { | ||
| // Bash foo from https://stackoverflow.com/a/47677632/4746236 | ||
| // Use bash instead of PHP as at least on Windows ~/dev/git/gerrit/mediawiki/core//.git returns false with file_exists when it really does | ||
| // TODO move to LS shell file? | ||
| return (int)trim(shell_exec('(ls ' . $this->getRealPath().'/.git' . ' >> /dev/null 2>&1 && echo 1) || echo 0')); | ||
| } | ||
|
|
||
| public function __toString() { | ||
| return $this->getRealPath(); | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Shell; | ||
|
|
||
| class Docker { | ||
|
|
||
| private const D = "docker"; | ||
|
|
||
| public function cp( string $source, string $target ) { | ||
| $shell = self::D . " cp ${source} ${target}"; | ||
| passthru( $shell ); | ||
| } | ||
|
|
||
| public function runComposerInstall( string $dir ) { | ||
| // TODO should this method be somewhere else? | ||
| $homeComposerMntString = ""; | ||
| // TODO make this ALWAYS mount the directory...? | ||
| // Otherwise the following happens... | ||
| // Cannot create cache directory /tmp/cache/repo/https---repo.packagist.org/, or directory is not writable. Proceeding without cache | ||
| // Cannot create cache directory /tmp/cache/files/, or directory is not writable. Proceeding without cache | ||
| if( file_exists( getenv('HOME') . '/.composer' ) ) { | ||
| // Note: this relies on the fact that the COMPOSER_HOME value is set to /tmp in the image by default. | ||
| $homeComposerMntString = "-v " . getenv('HOME') . '/.composer' . ":/tmp"; | ||
| } | ||
|
|
||
| // This runs with the running user id, which is good and means no chown is needed... | ||
| $shell = self::D . " run -it --rm --user $(id -u):$(id -g) ${homeComposerMntString} -v ${dir}:/app composer install --ignore-platform-reqs"; | ||
| passthru( $shell ); | ||
| } | ||
|
|
||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Shell; | ||
|
|
||
| use Addshore\Mwdd\Files\DotEnv; | ||
|
|
||
| class DockerCompose { | ||
|
|
||
| private $cmd; | ||
|
|
||
| public function __construct() { | ||
| $cmd = "docker-compose --project-directory . -p mediawiki-docker-dev"; | ||
| foreach( $this->getAllYmlFiles() as $file ) { | ||
| $cmd .= " -f ${file}"; | ||
| } | ||
| $this->cmd = $cmd; | ||
| } | ||
|
|
||
| /** | ||
| * The .env file must exist to run docker-compose commands without it screaming WARNING for no env vars.. | ||
| * This would often be a problem on first initialization | ||
| */ | ||
| private function ensureDotEnv() { | ||
| $dotEnv = new DotEnv(); | ||
| if(!$dotEnv->exists()) { | ||
| $dotEnv->updateFromDefaultAndLocal(); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @param string $fullCommand including docker-compose | ||
| */ | ||
| private function passthruDc( string $fullCommand ) { | ||
| $this->ensureDotEnv(); | ||
| passthru( $fullCommand ); | ||
| } | ||
|
|
||
| /** | ||
| * @return string[] of files for example "docker-compose/foo.yml" | ||
| */ | ||
| private function getAllYmlFiles () : array { | ||
| $files = array_diff(scandir('docker-compose'), array('.', '..')); | ||
| array_walk( $files, function( &$value ) { | ||
| $value = 'docker-compose/' . $value; | ||
| } ); | ||
| return $files; | ||
| } | ||
|
|
||
| /** | ||
| * @param string[] $services | ||
| * @param bool $build Should the --build flag be passed? | ||
| */ | ||
| public function upDetached( array $services, $build = false ) { | ||
| $buildString = $build ? ' --build' : ''; | ||
| $shell = $this->cmd . " up -d ${buildString} " . implode( ' ', $services ); | ||
| $this->passthruDc( $shell ); | ||
| } | ||
|
|
||
| public function downWithVolumesAndOrphans() { | ||
| $shell = $this->cmd . " down --volumes --remove-orphans"; | ||
| $this->passthruDc( $shell ); | ||
| } | ||
|
|
||
| public function stop( array $services ) { | ||
| $shell = $this->cmd . " stop " . implode( ' ', $services ); | ||
| $this->passthruDc( $shell ); | ||
| } | ||
|
|
||
| public function start( array $services ) { | ||
| $shell = $this->cmd . " start " . implode( ' ', $services );; | ||
| $this->passthruDc( $shell ); | ||
| } | ||
|
|
||
| // Command in an already running container | ||
| public function exec( string $service, $command, $extraArgString = '' ) { | ||
| $shell = $this->cmd . " exec ${extraArgString} \"${service}\" ${command}"; | ||
| $this->passthruDc( $shell ); | ||
| } | ||
|
|
||
| // Command in an already running container | ||
| public function execIt( string $service, $command, $extraArgString = '' ) { | ||
| $shell = $this->cmd . " exec -e COLUMNS=$(tput cols) -e LINES=$(tput lines) ${extraArgString} \"${service}\" ${command}"; | ||
| $this->passthruDc( $shell ); | ||
| } | ||
|
|
||
| // Command in a new container | ||
| public function run( string $service, $command, $extraArgString = '' ) { | ||
| $shell = $this->cmd . " run ${extraArgString} ${service} ${command}"; | ||
| $this->passthruDc( $shell ); | ||
| } | ||
|
|
||
| // Command in a new container | ||
| public function runDetatched( string $service, $command, $extraArgString = '' ) { | ||
| $shell = $this->cmd . " run -d ${extraArgString} \"${service}\" ${command}"; | ||
| // TODO should this actually passthru, given it is detached?? | ||
| $this->passthruDc( $shell ); | ||
| } | ||
|
|
||
| public function psQ( string $service ) { | ||
| $shell = $this->cmd . " ps -q ${service}"; | ||
| $output = shell_exec( $shell ); | ||
| return trim( $output ); | ||
| } | ||
|
|
||
| public function ps() { | ||
| $shell = $this->cmd . " ps"; | ||
| $this->passthruDc( $shell ); | ||
| } | ||
|
|
||
| public function logsTail( string $service, int $lines = 25 ) { | ||
| $shell = $this->cmd . " logs --tail=${lines} -f ${service}"; | ||
| $this->passthruDc( $shell ); | ||
| } | ||
|
|
||
| public function raw( string $rawCommand ) { | ||
| $shell = $this->cmd . " ${rawCommand}"; | ||
| $this->passthruDc( $shell ); | ||
| } | ||
|
|
||
|
|
||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Shell; | ||
|
|
||
| class Git { | ||
|
|
||
| private const G = "git"; | ||
|
|
||
| public function clone( string $repo, string $target, ?int $depth = 1 ) { | ||
| $depthString = $depth ? "--depth ${depth}" : ""; | ||
| $shell = self::G . " clone ${depthString} ${repo} $target"; | ||
| passthru( $shell ); | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| <?php | ||
|
|
||
| namespace Addshore\Mwdd\Shell; | ||
|
|
||
| class Id { | ||
|
|
||
| private const I = "id"; | ||
|
|
||
| public function ug() { | ||
| return $this->u() . ':' . $this->g(); | ||
| } | ||
|
|
||
| public function u() { | ||
| $shell = self::I . " -u"; | ||
| return trim( shell_exec( $shell ) ); | ||
| } | ||
|
|
||
| public function g() { | ||
| $shell = self::I . " -g"; | ||
| return trim( shell_exec( $shell ) ); | ||
| } | ||
|
|
||
| } |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| version: '2.2' | ||
|
|
||
| services: | ||
| adminer: | ||
| image: adminer | ||
| environment: | ||
| - VIRTUAL_HOST=adminer.mw.localhost | ||
| depends_on: | ||
| - dps | ||
| - nginx-proxy | ||
| hostname: adminer.mw.localhost | ||
| dns: | ||
| - 172.0.0.10 | ||
| networks: | ||
| - dps |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| version: '2.2' | ||
|
|
||
| services: | ||
|
|
||
| dps: | ||
| image: defreitas/dns-proxy-server | ||
| volumes: | ||
| - /var/run/docker.sock:/var/run/docker.sock | ||
| hostname: dps.mw.localhost | ||
| networks: | ||
| dps: | ||
| ipv4_address: 172.0.0.10 | ||
|
|
||
| nginx-proxy: | ||
| # TODO: replace with jwilder/nginx-proxy, once updated | ||
| image: silvanwmde/nginx-proxy:latest | ||
| environment: | ||
| - VIRTUAL_HOST=proxy.mw.localhost | ||
| - HOSTNAMES=.web.mw.localhost # wildcard name resolution, thanks to DPS | ||
| - HTTP_PORT=${DOCKER_MW_PORT} # internal port | ||
| ports: | ||
| - "${DOCKER_MW_PORT}:${DOCKER_MW_PORT}" | ||
| depends_on: | ||
| - dps | ||
| hostname: proxy.mw.localhost | ||
| dns: | ||
| - 172.0.0.10 | ||
| dns_search: | ||
| - mw.localhost | ||
| networks: | ||
| - dps | ||
| volumes: | ||
| - /var/run/docker.sock:/tmp/docker.sock:ro | ||
| - ./config/nginx/client_max_body_size.conf:/etc/nginx/conf.d/client_max_body_size.conf:ro | ||
| - ./config/nginx/timeouts.conf:/etc/nginx/conf.d/timeouts.conf:ro | ||
|
|
||
| networks: | ||
| dps: | ||
| ipam: | ||
| config: | ||
| - subnet: 172.0.0.0/24 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| version: '2.2' | ||
|
|
||
| services: | ||
| control: | ||
| scale: 0 | ||
| build: ./control | ||
| # The image tag should be updated whenever new composer dependencies are added... | ||
| image: mwdd-control:2020-05-13-19-44 | ||
| volumes: | ||
| - ./:/mwdd | ||
| - /var/run/docker.sock:/var/run/docker.sock |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| version: '2.2' | ||
|
|
||
| services: | ||
| db-replica: | ||
| image: ${DB}:latest | ||
| environment: | ||
| - MYSQL_ROOT_PASSWORD=toor | ||
| hostname: db-replica.mw.localhost | ||
| depends_on: | ||
| - db-master | ||
| dns: | ||
| - 172.0.0.10 | ||
| networks: | ||
| - dps | ||
| volumes: | ||
| - sql-data-replica:/var/lib/mysql | ||
| - ./config/mysql/replica:/mwdd-custom | ||
| entrypoint: "/mwdd-custom/entrypoint.sh" | ||
| command: "mysqld" | ||
|
|
||
| db-replica-configure-replication: | ||
| image: ${DB}:latest | ||
| environment: | ||
| - "MYSQL_REPLICA_PASSWORD=toor" | ||
| - "MYSQL_MASTER_PASSWORD=toor" | ||
| - "MYSQL_ROOT_PASSWORD=toor" | ||
| - "MYSQL_REPLICATION_USER=repl" | ||
| - "MYSQL_REPLICATION_PASSWORD=repl" | ||
| depends_on: | ||
| - db-replica | ||
| networks: | ||
| - dps | ||
| volumes: | ||
| - ./config/wait-for-it.sh:/wait-for-it.sh:ro | ||
| - ./config/mysql/replica:/mwdd-custom | ||
| - db-data-configure-replication:/mwdd-connector | ||
| command: /bin/bash -x /mwdd-custom/mysql_connector_replica.sh | ||
|
|
||
| volumes: | ||
| sql-data-replica: |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| version: '2.2' | ||
|
|
||
| services: | ||
| db-master: | ||
| image: ${DB}:latest | ||
| environment: | ||
| - MYSQL_ROOT_PASSWORD=toor | ||
| hostname: db-master.mw.localhost | ||
| dns: | ||
| - 172.0.0.10 | ||
| networks: | ||
| - dps | ||
| volumes: | ||
| - db-data-master:/var/lib/mysql | ||
| - ./config/mysql/master:/mwdd-custom | ||
| entrypoint: "/mwdd-custom/entrypoint.sh" | ||
| command: "mysqld" | ||
| depends_on: | ||
| # This feels like a backward dependancy, but it makes sense as the replication configure services waits for the master anyway. | ||
| # and whenever the master is created we want the configure replciation service to run to write the initial file and position for replication.. | ||
| - db-master-configure-replication | ||
|
|
||
| db-master-configure-replication: | ||
| image: ${DB}:latest | ||
| environment: | ||
| - "MYSQL_REPLICA_PASSWORD=toor" | ||
| - "MYSQL_MASTER_PASSWORD=toor" | ||
| - "MYSQL_ROOT_PASSWORD=toor" | ||
| - "MYSQL_REPLICATION_USER=repl" | ||
| - "MYSQL_REPLICATION_PASSWORD=repl" | ||
| networks: | ||
| - dps | ||
| volumes: | ||
| - ./config/wait-for-it.sh:/wait-for-it.sh:ro | ||
| - ./config/mysql/master:/mwdd-custom | ||
| - db-data-configure-replication:/mwdd-connector | ||
| command: /bin/bash -x /mwdd-custom/mysql_connector_master.sh | ||
|
|
||
| volumes: | ||
| db-data-master: | ||
| db-data-configure-replication: |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| version: '2.2' | ||
|
|
||
| # This service only exists to be able to run composer in its own container against the mediawiki code.. | ||
| # docker-compose doesnt allow a container to be run unless a service has already been creased, so we need this... | ||
|
|
||
| services: | ||
| mw-composer: | ||
| image: composer | ||
| # Run as the host user as this might create files... | ||
| user: "${UID}:${GID}" | ||
| networks: | ||
| - dps | ||
| dns: | ||
| - 172.0.0.10 | ||
| volumes: | ||
| # Only mount code and config, don't mount logs or image | ||
| # TODO is this bit of config even needed? | ||
| - "${DOCKER_MW_PATH}:/app:cached" | ||
| - ./config/mediawiki:/app/.docker:ro |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| version: '2.2' | ||
|
|
||
| # Service wrapper around what is provided by fresh | ||
| # https://github.com/wikimedia/fresh/blob/master/bin/fresh-node10 | ||
|
|
||
| services: | ||
| mw-fresh: | ||
| image: docker-registry.wikimedia.org/releng/node10-test-browser:0.6.1 | ||
| user: "${UID}:${GID}" | ||
| entrypoint: /bin/sh | ||
| command: -c "echo started" | ||
| working_dir: /app | ||
| networks: | ||
| - dps | ||
| dns: | ||
| - 172.0.0.10 | ||
| environment: | ||
| # https://www.mediawiki.org/wiki/Selenium/How-to/Run_tests_targeting_MediaWiki-Docker_using_Fresh#Environment_variables | ||
| - MW_SERVER=http://default.web.mw.localhost:${DOCKER_MW_PORT} | ||
| - MW_SCRIPT_PATH=/mediawiki | ||
| - MEDIAWIKI_USER=Admin | ||
| - MEDIAWIKI_PASSWORD=dockerpass | ||
| volumes: | ||
| # Only mount code and config, don't mount logs or image | ||
| # TODO is this bit of config even needed? | ||
| - "${DOCKER_MW_PATH}:/app:cached" | ||
| - ./config/mediawiki:/app/.docker:ro |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| version: '2.2' | ||
|
|
||
| # Service wrapper around what is provided by fresh | ||
| # https://github.com/wikimedia/fresh/blob/master/bin/fresh-node10 | ||
|
|
||
| services: | ||
| mw-quibble: | ||
| image: docker-registry.wikimedia.org/releng/quibble-stretch-php72:latest | ||
| user: "${UID}:${GID}" | ||
| entrypoint: /bin/sh | ||
| command: -c "echo started" | ||
| working_dir: /src | ||
| networks: | ||
| - dps | ||
| dns: | ||
| - 172.0.0.10 | ||
| volumes: | ||
| # Only mount code and config, don't mount logs or image | ||
| # TODO is this bit of config even needed? | ||
| - "${DOCKER_MW_PATH}:/workspace/src:cached" | ||
| - ./config/mediawiki:/workspace/src/.docker:ro | ||
| # TODO cache should be mounted from the user machine? | ||
| - mw-quibble-workspace-cache:/workspace/cache | ||
| - mw-quibble-workspace-log:/workspace/log | ||
| - mw-quibble-workspace-ref:/workspace/ref | ||
|
|
||
| volumes: | ||
| mw-quibble-workspace-cache: | ||
| mw-quibble-workspace-log: | ||
| mw-quibble-workspace-ref: |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| version: '2.2' | ||
|
|
||
| services: | ||
|
|
||
| mediawiki: | ||
| image: webdevops/php-${WEBSERVER}-dev:${RUNTIMEVERSION} | ||
| environment: | ||
| # Used by various maintenance scripts to find MediaWiki. | ||
| # Also required for /var/www/index.php - https://phabricator.wikimedia.org/T153882 | ||
| - MW_INSTALL_PATH=/app | ||
| - VIRTUAL_HOST=*.web.mw.localhost | ||
| - PHP_DEBUGGER=xdebug | ||
| - XDEBUG_REMOTE_AUTOSTART=${XDEBUG_REMOTE_AUTOSTART} | ||
| - XDEBUG_REMOTE_HOST=${IDELOCALHOST} | ||
| - XDEBUG_REMOTE_PORT=9000 | ||
| - XDEBUG_REMOTE_CONNECT_BACK=0 | ||
| - XDEBUG_PROFILER_ENABLE_TRIGGER=1 | ||
| - PHP_IDE_CONFIG=serverName=docker | ||
| - PHP_UPLOAD_MAX_FILESIZE=1024M | ||
| - PHP_POST_MAX_SIZE=1024M | ||
| - php.apc.enable_cli=1 | ||
| # The below env var is not needed by the container, only by MWDD | ||
| - MWDD_LOG_DIR=/var/log/mediawiki/ | ||
| hostname: mediawiki.mw.localhost | ||
| depends_on: | ||
| - db-master | ||
| - nginx-proxy | ||
| dns: | ||
| - 172.0.0.10 | ||
| dns_search: | ||
| - mw.localhost | ||
| networks: | ||
| - dps | ||
| volumes: | ||
| - "${DOCKER_MW_PATH}:/app:cached" | ||
| - ./config/mediawiki:/mwdd-custom:ro | ||
| - ./config/wait-for-it.sh:/wait-for-it.sh:ro | ||
| - mw-images:/app/images/docker:delegated | ||
| - "${DOCKER_MW_LOG_VOLUME}:/var/log/mediawiki:delegated" | ||
|
|
||
| volumes: | ||
| mw-logs: | ||
| mw-images: |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| version: '2.2' | ||
|
|
||
| services: | ||
| phpmyadmin: | ||
| image: phpmyadmin/phpmyadmin | ||
| environment: | ||
| - PMA_USER=root | ||
| - PMA_PASSWORD=toor | ||
| - PMA_HOSTS=db-master,db-replica | ||
| - PMA_ARBITRARY=1 | ||
| - VIRTUAL_HOST=phpmyadmin.mw.localhost | ||
| depends_on: | ||
| - dps | ||
| - nginx-proxy | ||
| hostname: phpmyadmin.mw.localhost | ||
| dns: | ||
| - 172.0.0.10 | ||
| networks: | ||
| - dps | ||
| volumes: | ||
| - ./config/phpmyadmin/config.user.inc.php:/etc/phpmyadmin/config.user.inc.php |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| version: '2.2' | ||
|
|
||
| services: | ||
| redis: | ||
| image: redis | ||
| hostname: redis.mw.localhost | ||
| dns: | ||
| - 172.0.0.10 | ||
| networks: | ||
| - dps |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| version: '2.2' | ||
|
|
||
| services: | ||
| graphite-statsd: | ||
| image: hopsoft/graphite-statsd | ||
| environment: | ||
| - VIRTUAL_HOST=graphite.mw.localhost | ||
| hostname: graphite.mw.localhost | ||
| dns: | ||
| - 172.0.0.10 | ||
| networks: | ||
| - dps | ||
| volumes: | ||
| - graphite-statsd-data:/opt/graphite/storage | ||
|
|
||
| volumes: | ||
| graphite-statsd-data: |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| #!/bin/bash | ||
|
|
||
| # Allow the user to force and env, but default to php for now.. | ||
| MWDD_ENV=${MWDD_ENV:-"php"} | ||
|
|
||
| # ### PHP only version.... | ||
| if [[ $MWDD_ENV == "php" ]] | ||
| then | ||
| php control/app.php $@ | ||
| fi | ||
|
|
||
| # ### Run everything in docker.. via docker-compose | ||
| if [[ $MWDD_ENV == "dc" ]] | ||
| then | ||
| # If control container is not already running, then we need to run up | ||
| CONTROL_CONTAINER_ID=$(docker-compose --project-directory . -p mediawiki-docker-dev -f docker-compose/control.yml ps --services --filter "status=running") | ||
| if [ -z "$CONTROL_CONTAINER_ID" ]; then | ||
|
|
||
| docker-compose \ | ||
| --project-directory . \ | ||
| -p mediawiki-docker-dev \ | ||
| -f docker-compose/control.yml \ | ||
| up -d --build \ | ||
| control | ||
| fi | ||
|
|
||
| # Then run the command | ||
| # This currently runs as root | ||
| # We could pass in the uid and gid, but then by default it would not be able to access the docker socket unless we also tweaked more things | ||
| docker-compose \ | ||
| --project-directory . \ | ||
| -p mediawiki-docker-dev \ | ||
| -f docker-compose/control.yml \ | ||
| exec \ | ||
| control \ | ||
| php control/app.php $@ | ||
| fi |
This file was deleted.