Compare commits

...

10 commits

Author SHA1 Message Date
k----n
e1dfdc65f2
Fetch networks instead of volumes (#59) 2022-01-18 15:08:25 +01:00
Julien BIANCHI
3ff9b0ccff
feat: Add GraphViz renderer (#53)
This will allow users to use the `dot` executable to produce any
supported output. For example, as requested in #52, one can now output a
SVG file. Here is an example:

```bash
bin/dcv render -m graphviz -o output.svg --graphviz-output-format svg
```

Closes #52
2020-08-19 19:40:57 +02:00
markiewb
60b3599c63
Update readme.md with troubleshooting of #41 (#51)
It has been proposed by others to include it in the readme.md
2020-07-29 21:39:24 +02:00
jubianchi
d1ef03be39
chore: Update copyright year 2020-07-23 23:11:19 +02:00
jubianchi
edaad5164c
chore: Fix workflow name 2020-07-23 22:45:01 +02:00
Julien BIANCHI
8cbae63adf
docs: Add a PowerShell example (#50)
thanks @PramodKumarYadav for the hint

Closes #44
2020-07-23 22:42:16 +02:00
Julien BIANCHI
03ab873e22
fix: Volume labels are correct (#49)
Closes #45
2020-07-23 22:35:06 +02:00
Julien BIANCHI
e1ad47ee9e
chore: Add github workflows (#48) 2020-07-23 22:26:42 +02:00
Grégory PLANCHAT
ead07e8fa9
Fixed the case where a service has no external file to import (#47) 2020-07-23 21:38:18 +02:00
Julien BIANCHI
bf8d4b200f
chore: Update PHP version (#46)
Closes #38
2020-07-23 21:10:34 +02:00
12 changed files with 211 additions and 150 deletions

30
.github/workflows/Deploy.yml vendored Normal file
View file

@ -0,0 +1,30 @@
name: Deploy
on:
push:
branches:
- master
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Cache Composer packages
id: composer-cache
uses: actions/cache@v2
with:
path: vendor
key: ${{ runner.os }}-node-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-node-
- name: Build and push Docker images
uses: docker/build-push-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
repository: pmsipilot/docker-compose-viz
tag_with_ref: true

43
.github/workflows/Test.yml vendored Normal file
View file

@ -0,0 +1,43 @@
name: Test
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Validate composer.json
run: composer validate --ansi --strict
- name: Cache Composer packages
id: composer-cache
uses: actions/cache@v2
with:
path: vendor
key: ${{ runner.os }}-node-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install dependencies
if: steps.composer-cache.outputs.cache-hit != 'true'
run: composer install --prefer-dist --no-progress --no-suggest
- name: Unit tests
run: composer run ut
- name: Coding style
run: composer run cst
- name: Build and push Docker images
uses: docker/build-push-action@v1
with:
push: false

11
.php_cs
View file

@ -1,15 +1,18 @@
<?php <?php
use PhpCsFixer as CS; $finder = PhpCsFixer\Finder::create()
$finder = CS\Finder::create()
->in(__DIR__.DIRECTORY_SEPARATOR.'src') ->in(__DIR__.DIRECTORY_SEPARATOR.'src')
->in(__DIR__.DIRECTORY_SEPARATOR.'spec') ->in(__DIR__.DIRECTORY_SEPARATOR.'spec')
; ;
return CS\Config::create() return (new PhpCsFixer\Config())
->setRules([ ->setRules([
'@PSR2' => true,
'@Symfony' => true, '@Symfony' => true,
'array_syntax' => ['syntax' => 'short'],
'no_useless_else' => true,
'no_useless_return' => true,
'ordered_class_elements' => true,
]) ])
->setFinder($finder) ->setFinder($finder)
; ;

View file

@ -1,54 +0,0 @@
language: php
sudo: required
services:
- docker
php:
- 7.0
- 7.1
- 7.2
- nightly
env:
matrix:
- COMPOSERFLAGS=
- COMPOSERFLAGS=--prefer-lowest
- COMPOSERFLAGS=--prefer-stable
global:
# DOCKER_EMAIL
- secure: JAbpFtQJovMT1IqHJmSlVI3xQpLUoqDlbYXUgExK99dH7+GH78Rd6CgjCo5fDAw5KW4zBoTJut7BWv+qdF1j9qpUEXlxB6dEwKdLHCCM8M9p+BddkaZUWF9kG+4pC1h6AeDeWi7Q77TzrOX7VAP1UubFOPItRNayF99zCJH6ioh8qnHNi2XHedIagMW4PGLp6HmTuyhzdF6RVEXcCos2fpkx5wzcjALb/ffN8A0dqtfELRvs6bjaQZ1ktmNjd3fSnQOtGO14VOei8E58e4roZNdDHMoIxzeqaM+bphsTZvHne4DAZEn3wU2iguzXLZMCAgF336Inu+t2Rjv4UDLcPeppMrYA+02Ww0kbCXcIQx4Og0Un54SY5qdIHZtnTXA+SAFr+5r+T80p29Tlp9cUfxaHWFynDEEDWx7minAATweSQU50ipPnAkge1WY/ADSN1EARqM2GYVQYLvddIaTSIbnq37MnlncWL+jkcQ0cL83xidYd7JnQ7/gZJf9MzeZzMVXrY+2VYL1WOrv1uwmVi30bpQss1D7IVVtN5iBlB2ciph+iHdvkhv6f8ji9xZmWkotfDzsRoZg7csDAVgliz55QkJYKeWDoiW7kb1i+pIsgmrdEonPMg7NHjSqIIkrwI89016Tsx4LH1t2sRRYW8Z7wuVhW3VcJD+CnkhAWvLc=
# DOCKER_USER
- secure: "bdD/Sg7IvpY/qLBK8KiaMBihGx00sj+K3+qHnHoqzqqzF6NjZFgfeJfhvVRLz84JPxTqDOcISwAfCvrV/cmtQkFVI7UP5Xg2GniTH8VGJxhBQxCmqLGd1tOLR9PPGtEh4HcjybGcOcIE3zn0xHhTwgS6jLxrrwPeapDAc+BYJcbbyrT1tjy5mv+wR3HmB2p5oiRhUL3P6u1+ND/j2oDZDoSllNRs+5jTiSXToIlXjICr6f8bey5DfOpGEAnopMXqSQmcf92C9dixfWprk0KE2MvELbE4hWtuu44FPLJcXbrMunKpFOiN1IfIxU2CXjlYpG9vcroJe3hZWpXG9ZY9nn5KDv+6H48zu+CQgZx0uobBaNmVFOXxiqDElb/kjjF6+Xx55JxGuRpcsGNdsbqU6qwTJmgeBv1UPLGste3BHY5dQkf10QbxXJmHgF1GQihS5mjpf1cobNMra0JxIFDUfpedB3cnFoM+masxKY6fexu9hXb3d5Yi7DKsHA2JUGayVCaGjcJEYYBzNLlNs9NbMcQHqfQ6a90HM1yH11DKMPWEGkvp7+M1ixjOUpTYng5yrOhgl624LDsNu/NwadtKTrk3wO9liyOJgojTUvbpVlB9potFf8vtX8JhKqGyOcMgaOx8VZt+gIL1W25hHtmEYglsfkEze3fOwWW8o4CBI2E="
# DOCKER_PASS
- secure: "BqpmNofWU38cV3eUT9Hm9wxiiRlp1LKl1JQBxvsYng/dk4L7ONiBVsrG6T7nYhkTktWc/II4ZAoQ7AGHN42W1quzSmc6d0fszQ7uTwNobfFQu2JzFNkhyP9D6b0v8uXhT8n6TPqOGgoJUcguStvasG3TuZwn7+PhwjyVfnzf+DhyaXjCljMatg7ekL0JDPGdAz/SQhuBiwk2xlZtxtEokNy7IVr9VcMi2O0nG3LMhCl1sQjo3JKBxPsalQi78dShDUHcazAE68T7M1FjAZCJYia902FMDWiIuujLamq+NpDgEKB3aLCLwF/o3j8z3ekPrk2v9Zokz+t36cQ2BmPpwqFfhvPdUv9tj9bi7Qv2R4NKreX8TWB8KB5afSVWiKfufWV5hp5KfwEmcLBc/hQdjRIwzDqVPK/fyy/GJ5fT4X5kz+YYLQEFxeWPtxL+OpQUXx2P5iDhx5qz173lO4h1WX4vEQ3p4aFbfnNREUDPGYsMJo6flm5Azq8F0qh065sxPldKunr9H4fAXrFzqMJnTepReEGPNJRn35TLl08RI7GTp0hKxlaycsu+c2Qz0/GcKbODWf5w24d/pxrOMM9KmJpDZTBm9bWiZlRbbZm1OnK0PiaRi9ft44Em5NYTFVvuWL2M2tIyGObI3kquKTkANvrSuPTofJ0JawXg2YBKOH8="
matrix:
exclude:
- php: 7.0
env: COMPOSERFLAGS=
- php: 7.1
env: COMPOSERFLAGS=--prefer-lowest
- php: 7.2
env: COMPOSERFLAGS=--prefer-lowest
- php: nightly
env: COMPOSERFLAGS=--prefer-lowest
allow_failures:
- php: nightly
script:
- make test
deploy:
- provider: script
script: ci/deploy.sh
on:
php: 7.1
all_branches: master
- provider: script
script: ci/deploy.sh
on:
php: 7.1
tags: true

View file

@ -1,4 +1,16 @@
FROM php:7.1-alpine FROM php:7.4-alpine as builder
COPY composer.json /dcv/composer.json
COPY composer.lock /dcv/composer.lock
WORKDIR /dcv
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" && \
php composer-setup.php && \
php -r "unlink('composer-setup.php');" && \
php composer.phar install --prefer-dist
FROM php:7.4-alpine
RUN apk update && \ RUN apk update && \
apk add graphviz ttf-dejavu && \ apk add graphviz ttf-dejavu && \
@ -8,7 +20,7 @@ RUN apk update && \
COPY bin/ /dcv/bin COPY bin/ /dcv/bin
COPY src/ /dcv/src COPY src/ /dcv/src
COPY vendor/ /dcv/vendor COPY --from=builder /dcv/vendor /dcv/vendor
RUN chmod +x /dcv/bin/dcv RUN chmod +x /dcv/bin/dcv

View file

@ -1,5 +1,5 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2016 PMSIpilot Copyright (c) 2020 PMSIpilot
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the documentation files (the "Software"), to deal in the Software without restriction, including without limitation the

View file

@ -12,29 +12,23 @@ docker: docker.lock
test: vendor unit cs test: vendor unit cs
unit: vendor unit: vendor
$(PHP) bin/kahlan --pattern='*.php' --reporter=verbose --persistent=false --cc=true $(COMPOSER) run ut
cs: cs:
$(PHP) bin/php-cs-fixer fix --dry-run $(COMPOSER) run cst
fix-cs: fix-cs:
$(PHP) bin/php-cs-fixer fix $(COMPOSER) run cs
clean: clean:
rm -rf vendor/ rm -rf vendor/
docker.lock: Dockerfile bin/entrypoint.sh vendor src/application.php src/functions.php docker.lock: Dockerfile bin/entrypoint.sh vendor src/application.php src/functions.php
$(COMPOSER) dump-autoload --classmap-authoritative
$(DOCKER) build -t $(DCV_IMAGE_NAME) . $(DOCKER) build -t $(DCV_IMAGE_NAME) .
touch docker.lock touch docker.lock
ifndef COMPOSERFLAGS
vendor: composer.lock vendor: composer.lock
$(COMPOSER) install --prefer-dist $(COMPOSER) install --prefer-dist
else
vendor: composer.lock
$(COMPOSER) update $(COMPOSERFLAGS)
endif
composer.lock: composer.json composer.lock: composer.json
$(COMPOSER) update $(COMPOSERFLAGS) $(COMPOSER) update $(COMPOSERFLAGS)

View file

@ -1,7 +1,5 @@
# `docker-compose-viz` # `docker-compose-viz`
[![Build Status](https://img.shields.io/travis/pmsipilot/docker-compose-viz/master.svg?style=flat-square)](https://travis-ci.org/pmsipilot/docker-compose-viz)
[![StyleCI](https://styleci.io/repos/65026022/shield)](https://styleci.io/repos/65026022)
[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/pmsipilot/docker-compose-viz.svg)](http://isitmaintained.com/project/pmsipilot/docker-compose-viz "Average time to resolve an issue") [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/pmsipilot/docker-compose-viz.svg)](http://isitmaintained.com/project/pmsipilot/docker-compose-viz "Average time to resolve an issue")
[![Percentage of issues still open](http://isitmaintained.com/badge/open/pmsipilot/docker-compose-viz.svg)](http://isitmaintained.com/project/pmsipilot/docker-compose-viz "Percentage of issues still open") [![Percentage of issues still open](http://isitmaintained.com/badge/open/pmsipilot/docker-compose-viz.svg)](http://isitmaintained.com/project/pmsipilot/docker-compose-viz "Percentage of issues still open")
[![Docker Stars](https://img.shields.io/docker/stars/pmsipilot/docker-compose-viz.svg?style=flat)](https://hub.docker.com/r/pmsipilot/docker-compose-viz/) [![Docker Stars](https://img.shields.io/docker/stars/pmsipilot/docker-compose-viz.svg?style=flat)](https://hub.docker.com/r/pmsipilot/docker-compose-viz/)
@ -13,8 +11,11 @@
Considering the current working directory is where your `docker-compose.yml` file is located: Considering the current working directory is where your `docker-compose.yml` file is located:
``` ```bash
docker run --rm -it --name dcv -v $(pwd):/input pmsipilot/docker-compose-viz render -m image docker-compose.yml docker run --rm -it --name dcv -v $(pwd):/input pmsipilot/docker-compose-viz render -m image docker-compose.yml
# PowerShell
docker run --rm -it --name dcv -v ${pwd}:/input pmsipilot/docker-compose-viz render -m image docker-compose.yml
``` ```
This will generate the `docker-compose.png` file in the current working directory. This will generate the `docker-compose.png` file in the current working directory.
@ -24,7 +25,7 @@ This will generate the `docker-compose.png` file in the current working director
Before you start, make sure you have: Before you start, make sure you have:
* [Composer](https://getcomposer.org/doc/00-intro.md#installation-linux-unix-osx) installed, * [Composer](https://getcomposer.org/doc/00-intro.md#installation-linux-unix-osx) installed,
* [PHP 7](http://php.net/downloads.php#v7.0.9) installed, * [PHP 7.2](http://php.net/downloads.php#v7.2.32) (at least) installed,
* GraphViz installed (see below for a guide on how to install it) * GraphViz installed (see below for a guide on how to install it)
``` ```
@ -175,7 +176,14 @@ digraph G {
![display renderer](resources/display.png) ![display renderer](resources/display.png)
### Troubleshooting
#### Getting "failed to open stream: Permission denied"?
Make sure the target directory is writeable by the user in the Docker container.
Or create a writeable directory first. See [workaround #41](https://github.com/pmsipilot/docker-compose-viz/issues/41#issuecomment-483384999)
## License ## License
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2016 PMSIpilot Copyright ® 2020 PMSIpilot

View file

@ -2,15 +2,15 @@
"name": "pmsipilot/docker-compose-viz", "name": "pmsipilot/docker-compose-viz",
"description": "Docker compose graph visualization", "description": "Docker compose graph visualization",
"require": { "require": {
"php": "^7", "php": "^7.2",
"symfony/yaml": "^3.1 || ^4", "symfony/yaml": "^3.1 || ^4",
"symfony/console": "^3.1", "symfony/console": "^3.1",
"clue/graph": "^0.9", "clue/graph": "^0.9",
"graphp/graphviz": "^0.2" "graphp/graphviz": "^0.2"
}, },
"require-dev": { "require-dev": {
"crysalead/kahlan": "^2.5.4", "friendsofphp/php-cs-fixer": "^2",
"friendsofphp/php-cs-fixer": "^2" "kahlan/kahlan": "^4.7"
}, },
"license": "MIT", "license": "MIT",
"authors": [ "authors": [
@ -25,7 +25,9 @@
"PMSIpilot\\DockerComposeViz\\": "src/" "PMSIpilot\\DockerComposeViz\\": "src/"
} }
}, },
"config": { "scripts": {
"bin-dir": "bin/" "cs": "php-cs-fixer fix",
"cst": "php-cs-fixer fix --dry-run",
"ut": "kahlan --grep='*.php' --reporter=verbose --persistent=false"
} }
} }

112
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "e5370b9d4f890699543b1dbd6ba801de", "content-hash": "883183cc51537213776e61c66e969e5a",
"packages": [ "packages": [
{ {
"name": "clue/graph", "name": "clue/graph",
@ -626,58 +626,6 @@
], ],
"time": "2020-06-04T11:16:35+00:00" "time": "2020-06-04T11:16:35+00:00"
}, },
{
"name": "crysalead/kahlan",
"version": "2.5.8",
"source": {
"type": "git",
"url": "https://github.com/kahlan/kahlan.git",
"reference": "4fad70f5a81698fe6cae725b21bb08c4aa677788"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/kahlan/kahlan/zipball/4fad70f5a81698fe6cae725b21bb08c4aa677788",
"reference": "4fad70f5a81698fe6cae725b21bb08c4aa677788",
"shasum": ""
},
"require": {
"php": ">=5.4"
},
"bin": [
"bin/kahlan"
],
"type": "library",
"autoload": {
"psr-4": {
"Kahlan\\": "src/"
},
"files": [
"src/init.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "CrysaLEAD"
}
],
"description": "Behavior-Driven Development (BDD) library.",
"keywords": [
"BDD",
"Behavior-Driven Development",
"Monkey Patching",
"TDD",
"mock",
"stub",
"testing",
"unit test"
],
"abandoned": "kahlan/kahlan",
"time": "2016-09-29T01:40:20+00:00"
},
{ {
"name": "doctrine/annotations", "name": "doctrine/annotations",
"version": "1.10.3", "version": "1.10.3",
@ -900,6 +848,60 @@
"description": "A tool to automatically fix PHP code style", "description": "A tool to automatically fix PHP code style",
"time": "2020-06-27T23:57:46+00:00" "time": "2020-06-27T23:57:46+00:00"
}, },
{
"name": "kahlan/kahlan",
"version": "4.7.5",
"source": {
"type": "git",
"url": "https://github.com/kahlan/kahlan.git",
"reference": "c529ef24201053ba76d3c8c3531acd76b629ce87"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/kahlan/kahlan/zipball/c529ef24201053ba76d3c8c3531acd76b629ce87",
"reference": "c529ef24201053ba76d3c8c3531acd76b629ce87",
"shasum": ""
},
"require": {
"php": ">=5.5"
},
"require-dev": {
"squizlabs/php_codesniffer": "^3.4"
},
"bin": [
"bin/kahlan"
],
"type": "library",
"autoload": {
"psr-4": {
"Kahlan\\": "src/"
},
"files": [
"src/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "CrysaLEAD"
}
],
"description": "The PHP Test Framework for Freedom, Truth and Justice.",
"keywords": [
"BDD",
"Behavior-Driven Development",
"Monkey Patching",
"TDD",
"mock",
"stub",
"testing",
"unit test"
],
"time": "2020-04-25T21:27:19+00:00"
},
{ {
"name": "paragonie/random_compat", "name": "paragonie/random_compat",
"version": "v9.99.99", "version": "v9.99.99",
@ -1718,10 +1720,10 @@
"aliases": [], "aliases": [],
"minimum-stability": "stable", "minimum-stability": "stable",
"stability-flags": [], "stability-flags": [],
"prefer-stable": true, "prefer-stable": false,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {
"php": "^7" "php": "^7.2"
}, },
"platform-dev": [] "platform-dev": []
} }

View file

@ -12,7 +12,8 @@ $application->register('render')
->addOption('override', null, Console\Input\InputOption::VALUE_REQUIRED, 'Tag of the override file to use', 'override') ->addOption('override', null, Console\Input\InputOption::VALUE_REQUIRED, 'Tag of the override file to use', 'override')
->addOption('output-file', 'o', Console\Input\InputOption::VALUE_REQUIRED, 'Path to a output file (Only for "dot" and "image" output format)') ->addOption('output-file', 'o', Console\Input\InputOption::VALUE_REQUIRED, 'Path to a output file (Only for "dot" and "image" output format)')
->addOption('output-format', 'm', Console\Input\InputOption::VALUE_REQUIRED, 'Output format (one of: "dot", "image", "display")', 'display') ->addOption('output-format', 'm', Console\Input\InputOption::VALUE_REQUIRED, 'Output format (one of: "dot", "image", "display", "graphviz")', 'display')
->addOption('graphviz-output-format', null, Console\Input\InputOption::VALUE_REQUIRED, 'GraphViz Output format (see `man dot` for details)', 'svg')
->addOption('only', null, Console\Input\InputOption::VALUE_IS_ARRAY | Console\Input\InputOption::VALUE_REQUIRED, 'Display a graph only for a given services') ->addOption('only', null, Console\Input\InputOption::VALUE_IS_ARRAY | Console\Input\InputOption::VALUE_REQUIRED, 'Display a graph only for a given services')
->addOption('force', 'f', Console\Input\InputOption::VALUE_NONE, 'Overwrites output file if it already exists') ->addOption('force', 'f', Console\Input\InputOption::VALUE_NONE, 'Overwrites output file if it already exists')
@ -39,7 +40,7 @@ $application->register('render')
$outputFile = $input->getOption('output-file') ?: getcwd().DIRECTORY_SEPARATOR.'docker-compose.'.('dot' === $outputFormat ? $outputFormat : 'png'); $outputFile = $input->getOption('output-file') ?: getcwd().DIRECTORY_SEPARATOR.'docker-compose.'.('dot' === $outputFormat ? $outputFormat : 'png');
$onlyServices = $input->getOption('only'); $onlyServices = $input->getOption('only');
if (false === in_array($outputFormat, ['dot', 'image', 'display'])) { if (false === in_array($outputFormat, ['dot', 'image', 'display', 'graphviz'])) {
throw new Console\Exception\InvalidArgumentException(sprintf('Invalid output format "%s". It must be one of "dot", "image" or "display".', $outputFormat)); throw new Console\Exception\InvalidArgumentException(sprintf('Invalid output format "%s". It must be one of "dot", "image" or "display".', $outputFormat));
} }
@ -141,6 +142,13 @@ $application->register('render')
$renderer = new GraphViz(); $renderer = new GraphViz();
$renderer->display($graph); $renderer->display($graph);
break; break;
case 'graphviz':
$renderer = new GraphViz();
$format = $input->getOption('graphviz-output-format');
file_put_contents($outputFile, $renderer->setFormat($format)->createImageData($graph));
break;
} }
}); });

View file

@ -226,7 +226,8 @@ function makeVerticesAndEdges(Graph $graph, array $services, array $volumes, arr
if (false === ((bool) ($flags & WITHOUT_NETWORKS))) { if (false === ((bool) ($flags & WITHOUT_NETWORKS))) {
foreach ($networks as $network => $definition) { foreach ($networks as $network => $definition) {
addNetwork( addNetwork(
$graph, 'net: '.$network, $graph,
'net: '.$network,
isset($definition['external']) && true === $definition['external'] ? 'external_network' : 'network' isset($definition['external']) && true === $definition['external'] ? 'external_network' : 'network'
); );
} }
@ -236,12 +237,14 @@ function makeVerticesAndEdges(Graph $graph, array $services, array $volumes, arr
addService($graph, $service); addService($graph, $service);
if (isset($definition['extends'])) { if (isset($definition['extends'])) {
if (isset($definition['extends']['file'])) {
$configuration = readConfiguration(dirname($path).DIRECTORY_SEPARATOR.$definition['extends']['file']); $configuration = readConfiguration(dirname($path).DIRECTORY_SEPARATOR.$definition['extends']['file']);
$extendedServices = fetchServices($configuration); $extendedServices = fetchServices($configuration);
$extendedVolumes = fetchVolumes($configuration); $extendedVolumes = fetchVolumes($configuration);
$extendedNetworks = fetchVolumes($configuration); $extendedNetworks = fetchNetworks($configuration);
$graph = makeVerticesAndEdges($graph, $extendedServices, $extendedVolumes, $extendedNetworks, dirname($path).DIRECTORY_SEPARATOR.$definition['extends']['file'], $flags); $graph = makeVerticesAndEdges($graph, $extendedServices, $extendedVolumes, $extendedNetworks, dirname($path).DIRECTORY_SEPARATOR.$definition['extends']['file'], $flags);
}
addRelation( addRelation(
addService($graph, $definition['extends']['service']), addService($graph, $definition['extends']['service']),
@ -306,7 +309,7 @@ function makeVerticesAndEdges(Graph $graph, array $services, array $volumes, arr
$container = $volume['target']; $container = $volume['target'];
$attr = !empty($volume['read-only']) ? 'ro' : ''; $attr = !empty($volume['read-only']) ? 'ro' : '';
} else { } else {
list($host, $container, $attr) = explodeMapping($volume); list($host, $container, $attr) = explodeVolumeMapping($volume);
} }
$serviceVolumes[$container] = [$host, $attr]; $serviceVolumes[$container] = [$host, $attr];
@ -503,13 +506,23 @@ function explodeMapping($mapping): array
$parts = explode(':', $mapping); $parts = explode(':', $mapping);
$parts[1] = $parts[1] ?? $parts[0]; $parts[1] = $parts[1] ?? $parts[0];
$subparts = array_values(array_filter(explode('/', $parts[1]))); return [$parts[0], $parts[1]];
if (count($subparts) > 2) {
$subparts = [$parts[1], $parts[2] ?? null];
} }
return [$parts[0], $subparts[0], $subparts[1] ?? null]; /**
* @internal
*
* @param string $mapping A docker mapping (<from>[:<to>])
*
* @return array An 2 or 3 items array containing the parts of the mapping.
* If the mapping does not specify a second part, the first one will be repeated
*/
function explodeVolumeMapping($mapping): array
{
$parts = explode(':', $mapping);
$parts[1] = $parts[1] ?? $parts[0];
return [$parts[0], $parts[1], $parts[2] ?? null];
} }
/** /**