Skip to content

Commit

Permalink
Docker support (Docker Compose and Dockerfile)
Browse files Browse the repository at this point in the history
  • Loading branch information
dunglas committed Jun 26, 2019
1 parent cc58019 commit 78c2bec
Show file tree
Hide file tree
Showing 5 changed files with 708 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/Configurator.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ public function __construct(Composer $composer, IOInterface $io, Options $option
'makefile' => Configurator\MakefileConfigurator::class,
'composer-scripts' => Configurator\ComposerScriptsConfigurator::class,
'gitignore' => Configurator\GitignoreConfigurator::class,
'dockerfile' => Configurator\DockerfileConfigurator::class,
'docker-compose' => Configurator\DockerComposeConfigurator::class,
];
}

Expand Down
128 changes: 128 additions & 0 deletions src/Configurator/DockerComposeConfigurator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Flex\Configurator;

use Symfony\Flex\Lock;
use Symfony\Flex\Recipe;

/**
* Adds services and volumes to docker-compose.yml file.
*
* @author Kévin Dunglas <[email protected]>
*/
class DockerComposeConfigurator extends AbstractConfigurator
{
public function configure(Recipe $recipe, $config, Lock $lock, array $options = [])
{
$installDocker = $this->composer->getPackage()->getExtra()['symfony']['docker'] ?? false;
if (!$installDocker) {
return;
}

$rootDir = $this->options->get('root-dir');
if (
(
!file_exists($dockerComposeFile = $rootDir.'/docker-compose.yml') &&
!file_exists($dockerComposeFile = $rootDir.'/docker-compose.yaml')
) || $this->isFileMarked($recipe, $dockerComposeFile)
) {
return;
}

$this->write('Adding Docker Compose entries');

$offset = 8;
$node = null;
$endAt = [];
$lines = [];
foreach (file($dockerComposeFile) as $i => $line) {
$lines[] = $line;
$ltrimedLine = ltrim($line, ' ');

// Skip blank lines and comments
if (('' !== $ltrimedLine && 0 === strpos($ltrimedLine, '#')) || '' === trim($line)) {
continue;
}

// Extract Docker Compose keys (usually "services" and "volumes")
if (!preg_match('/^[\'"]?([a-zA-Z0-9]+)[\'"]?:\s*$/', $line, $matches)) {
// Detect indentation to use
$offestLine = \strlen($line) - \strlen($ltrimedLine);
if ($offset > $offestLine && 0 !== $offestLine) {
$offset = $offestLine;
}
continue;
}

// Keep end in memory (check break line on previous line)
$endAt[$node] = '' !== trim($lines[$i - 1]) ? $i : $i - 1;
$node = $matches[1];
}
$endAt[$node] = \count($lines) + 1;

foreach ($config as $key => $value) {
if (isset($endAt[$key])) {
array_splice($lines, $endAt[$key], 0, $this->markData($recipe, $this->parse(1, $offset, $value)));
continue;
}

$lines[] = sprintf("\n%s:", $key);
$lines[] = $this->markData($recipe, $this->parse(1, $offset, $value));
}

file_put_contents($dockerComposeFile, implode('', $lines));
}

public function unconfigure(Recipe $recipe, $config, Lock $lock)
{
$rootDir = $this->options->get('root-dir');
if (!file_exists($dockerCompose = $rootDir.'/docker-compose.yml') &&
!file_exists($dockerCompose = $rootDir.'/docker-compose.yaml')
) {
return;
}

$name = $recipe->getName();
// Remove recipe and add break line
$contents = preg_replace(sprintf('{%s+###> %s ###.*?###< %s ###%s+}s', "\n", $name, $name, "\n"), PHP_EOL.PHP_EOL, file_get_contents($dockerCompose), -1, $count);
if (!$count) {
return;
}

foreach ($config as $key => $value) {
if (0 === preg_match(sprintf('{^%s:[ \t\r\n]*([ \t]+\w)}m', $key), $contents, $matches)) {
$contents = preg_replace(sprintf('{\n?^%s:[ \t\r\n]*}sm', $key), '', $contents, -1, $count);
}
}

$this->write(sprintf('Removing Docker Compose entries from %s', $dockerCompose));
file_put_contents($dockerCompose, ltrim($contents, "\n"));
}

private function parse($level, $indent, $services): string
{
$line = '';
foreach ($services as $key => $value) {
$line .= str_repeat(' ', $indent * $level);
if (!\is_array($value)) {
if (\is_string($key)) {
$line .= sprintf('%s:', $key);
}
$line .= sprintf("%s\n", $value);
continue;
}
$line .= sprintf("%s:\n", $key).$this->parse($level + 1, $indent, $value);
}

return $line;
}
}
66 changes: 66 additions & 0 deletions src/Configurator/DockerfileConfigurator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Flex\Configurator;

use Symfony\Flex\Lock;
use Symfony\Flex\Recipe;

/**
* Adds commands to a Dockerfile.
*
* @author Kévin Dunglas <[email protected]>
*/
class DockerfileConfigurator extends AbstractConfigurator
{
public function configure(Recipe $recipe, $config, Lock $lock, array $options = [])
{
$installDocker = $this->composer->getPackage()->getExtra()['symfony']['docker'] ?? false;
if (!$installDocker) {
return;
}

$dockerfile = $this->options->get('root-dir').'/Dockerfile';
if (!file_exists($dockerfile) || $this->isFileMarked($recipe, $dockerfile)) {
return;
}

$this->write('Adding Dockerfile entries');

$lines = [];
foreach (file($dockerfile) as $line) {
$lines[] = $line;
if (!preg_match('/^###> recipes ###$/', $line)) {
continue;
}

$lines[] = ltrim($this->markData($recipe, implode("\n", $config)), "\n");
}

file_put_contents($dockerfile, implode('', $lines));
}

public function unconfigure(Recipe $recipe, $config, Lock $lock)
{
if (!file_exists($dockerfile = $this->options->get('root-dir').'/Dockerfile')) {
return;
}

$name = $recipe->getName();
$contents = preg_replace(sprintf('{%s+###> %s ###.*?###< %s ###%s+}s', "\n", $name, $name, "\n"), "\n", file_get_contents($dockerfile), -1, $count);
if (!$count) {
return;
}

$this->write('Removing Dockerfile entries');
file_put_contents($dockerfile, ltrim($contents, "\n"));
}
}
Loading

0 comments on commit 78c2bec

Please sign in to comment.