├── .github └── workflows │ └── docker.yml ├── .gitignore ├── Dockerfile ├── README.md ├── poetry.lock ├── pyproject.toml └── src ├── __init__.py └── autocompose.py /.github/workflows/docker.yml: -------------------------------------------------------------------------------- 1 | name: Build Multi Stage Docker Image 2 | on: 3 | push: 4 | branches-ignore: 5 | - 'dependabot/**' 6 | schedule: 7 | - cron: '0 5 * * *' 8 | 9 | jobs: 10 | GHRC: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v2.3.4 15 | 16 | - uses: FranzDiebold/github-env-vars-action@v2.3.0 17 | - name: Print environment variables 18 | run: | 19 | echo "CI_REPOSITORY_NAME=$CI_REPOSITORY_NAME" 20 | 21 | - name: Prepare GHRC.io 22 | id: prep 23 | run: | 24 | REPO=$CI_REPOSITORY_NAME 25 | OWNER="$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')" 26 | DOCKER_IMAGE=${OWNER}/${REPO} 27 | if [ "$CI_REF_NAME" == "master" ];then VERSION=latest;fi 28 | if [ "$CI_REF_NAME" == "dev" ];then VERSION=mightly;fi 29 | if [ "$CI_REF_NAME" == "dockserver" ];then VERSION=dockserver;fi 30 | TAGS="${DOCKER_IMAGE}:${VERSION}" 31 | echo ::set-output name=tags::${TAGS} 32 | echo ::set-output name=title::${GITHUB_REPOSITORY} 33 | echo ::set-output name=version::${VERSION} 34 | echo ::set-output name=created::$(date -u +'%Y-%m-%dT%H:%M:%SZ') 35 | 36 | - name: Set up QEMU 37 | uses: docker/setup-qemu-action@v1 38 | with: 39 | platforms: linux/amd64,linux/armhf,linux/arm64 40 | 41 | - name: Set up Docker Buildx 42 | id: buildx 43 | uses: docker/setup-buildx-action@v1.3.0 44 | 45 | - name: Cache Docker layers 46 | uses: actions/cache@v2.1.6 47 | with: 48 | path: /tmp/.buildx-cache 49 | key: ${{ runner.os }}-buildx-${{ github.sha }} 50 | restore-keys: | 51 | ${{ runner.os }}-buildx- 52 | 53 | - name: Login to GitHub Container Registry 54 | if: github.event_name != 'pull_request' 55 | uses: docker/login-action@v1.9.0 56 | with: 57 | registry: ghcr.io 58 | username: ${{ github.repository_owner }} 59 | password: ${{ secrets.CR_PAT }} 60 | 61 | - name: Build and push GHRC.io 62 | id: docker_build 63 | uses: docker/build-push-action@v2.5.0 64 | with: 65 | builder: ${{ steps.buildx.outputs.name }} 66 | context: . 67 | file: ./Dockerfile 68 | platforms: linux/amd64,linux/armhf,linux/arm64 69 | push: ${{ github.event_name != 'pull_request' }} 70 | tags: ghcr.io/${{ steps.prep.outputs.tags }} 71 | labels: | 72 | org.opencontainers.image.title=${{ steps.prep.outputs.title }} 73 | org.opencontainers.image.version=${{ steps.prep.outputs.version }} 74 | org.opencontainers.image.created=${{ steps.prep.outputs.created }} 75 | 76 | - name: Image digest 77 | run: echo ${{ steps.docker_build.outputs.digest }} 78 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # PyCharm 156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 158 | # and can be added to the global gitignore or merged into this file. For a more nuclear 159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 160 | #.idea/ 161 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.12-alpine 2 | LABEL org.opencontainers.image.source=https://github.com/Red5d/docker-autocompose 3 | WORKDIR /usr/src/app 4 | ENTRYPOINT [ "poetry", "run", "autocompose" ] 5 | 6 | RUN apk add --no-cache poetry 7 | 8 | COPY poetry.lock pyproject.toml README.md ./ 9 | COPY src ./src 10 | 11 | RUN poetry install 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # docker-autocompose 2 | Generates a docker-compose yaml definition from a docker container. 3 | 4 | Required Modules: 5 | * [pyaml](https://pypi.python.org/project/pyaml/) 6 | * [docker](https://pypi.python.org/project/docker) 7 | 8 | For building this project [poetry](https://python-poetry.org/) is required. Install it with the package manager of your OS or if that's impossible with `pip`. 9 | 10 | Install them: 11 | 12 | poetry install 13 | 14 | Example Usage: 15 | 16 | poetry run autocompose 17 | 18 | 19 | Generate a compose file for multiple containers together: 20 | 21 | poetry run autocompose apache-test mysql-test 22 | 23 | 24 | The script defaults to outputting to compose file version 3, but use "-v 1" to output to version 1: 25 | 26 | poetry run autocompose -v 1 apache-test 27 | 28 | 29 | Outputs a docker-compose compatible yaml structure: 30 | 31 | [docker-compose reference](https://docs.docker.com/compose/) 32 | 33 | [docker-compose yaml file specification](https://docs.docker.com/compose/compose-file/) 34 | 35 | While experimenting with various docker containers from the Hub, I realized that I'd started several containers with complex options for volumes, ports, environment variables, etc. and there was no way I could remember all those commands without referencing the Hub page for each image if I needed to delete and re-create the container (for updates, or if something broke). 36 | 37 | With this tool, I can easily generate docker-compose files for managing the containers that I've set up manually. 38 | 39 | ## Native installation 40 | 41 | System-wide installation is discouraged. If you really need to, you can run `pip install --user --break-system-packages .` (use at your own discretion). 42 | 43 | There are unofficial packages available in the Arch User Repository: 44 | * [Stable](https://aur.archlinux.org/packages/docker-autocompose) 45 | * [Development (follows the master branch)](https://aur.archlinux.org/packages/docker-autocompose-git) 46 | 47 | **AUR packages are provided by a third party and are not tested or updated by the maintainer(s) of the docker-autocompose project.** 48 | 49 | ## Docker Usage 50 | 51 | You can use this tool from a docker container by either cloning this repo and building the image or using the [automatically generated image on GitHub](https://github.com/Red5d/docker-autocompose/pkgs/container/docker-autocompose) 52 | 53 | Pull the image from GitHub (supports both x86 and ARM) 54 | 55 | docker pull ghcr.io/red5d/docker-autocompose:latest 56 | 57 | Use the new image to generate a docker-compose file from a running container or a list of space-separated container names or ids: 58 | 59 | docker run --rm -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/red5d/docker-autocompose ... 60 | 61 | To print out all containers in a docker-compose format: 62 | 63 | docker run --rm -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/red5d/docker-autocompose $(docker ps -aq) 64 | 65 | ## Contributing 66 | 67 | When making changes, please validate the output from the script by writing it to a file (docker-compose.yml or docker-compose.yaml) and running "docker-compose config" in the same folder with it to ensure that the resulting compose file will be accepted by docker-compose. 68 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "certifi" 5 | version = "2024.8.30" 6 | description = "Python package for providing Mozilla's CA Bundle." 7 | optional = false 8 | python-versions = ">=3.6" 9 | files = [ 10 | {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, 11 | {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, 12 | ] 13 | 14 | [[package]] 15 | name = "charset-normalizer" 16 | version = "3.4.0" 17 | description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." 18 | optional = false 19 | python-versions = ">=3.7.0" 20 | files = [ 21 | {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, 22 | {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, 23 | {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, 24 | {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, 25 | {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, 26 | {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, 27 | {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, 28 | {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, 29 | {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, 30 | {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, 31 | {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, 32 | {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, 33 | {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, 34 | {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, 35 | {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, 36 | {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, 37 | {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, 38 | {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, 39 | {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, 40 | {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, 41 | {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, 42 | {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, 43 | {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, 44 | {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, 45 | {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, 46 | {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, 47 | {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, 48 | {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, 49 | {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, 50 | {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, 51 | {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, 52 | {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, 53 | {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, 54 | {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, 55 | {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, 56 | {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, 57 | {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, 58 | {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, 59 | {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, 60 | {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, 61 | {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, 62 | {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, 63 | {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, 64 | {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, 65 | {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, 66 | {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, 67 | {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, 68 | {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, 69 | {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, 70 | {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, 71 | {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, 72 | {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, 73 | {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, 74 | {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, 75 | {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, 76 | {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, 77 | {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, 78 | {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, 79 | {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, 80 | {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, 81 | {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, 82 | {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, 83 | {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, 84 | {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, 85 | {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, 86 | {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, 87 | {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, 88 | {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, 89 | {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, 90 | {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, 91 | {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, 92 | {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, 93 | {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, 94 | {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, 95 | {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, 96 | {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, 97 | {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, 98 | {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, 99 | {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, 100 | {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, 101 | {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, 102 | {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, 103 | {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, 104 | {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, 105 | {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, 106 | {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, 107 | {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, 108 | {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, 109 | {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, 110 | {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, 111 | {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, 112 | {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, 113 | {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, 114 | {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, 115 | {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, 116 | {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, 117 | {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, 118 | {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, 119 | {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, 120 | {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, 121 | {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, 122 | {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, 123 | {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, 124 | {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, 125 | {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, 126 | ] 127 | 128 | [[package]] 129 | name = "docker" 130 | version = "7.1.0" 131 | description = "A Python library for the Docker Engine API." 132 | optional = false 133 | python-versions = ">=3.8" 134 | files = [ 135 | {file = "docker-7.1.0-py3-none-any.whl", hash = "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0"}, 136 | {file = "docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c"}, 137 | ] 138 | 139 | [package.dependencies] 140 | pywin32 = {version = ">=304", markers = "sys_platform == \"win32\""} 141 | requests = ">=2.26.0" 142 | urllib3 = ">=1.26.0" 143 | 144 | [package.extras] 145 | dev = ["coverage (==7.2.7)", "pytest (==7.4.2)", "pytest-cov (==4.1.0)", "pytest-timeout (==2.1.0)", "ruff (==0.1.8)"] 146 | docs = ["myst-parser (==0.18.0)", "sphinx (==5.1.1)"] 147 | ssh = ["paramiko (>=2.4.3)"] 148 | websockets = ["websocket-client (>=1.3.0)"] 149 | 150 | [[package]] 151 | name = "idna" 152 | version = "3.10" 153 | description = "Internationalized Domain Names in Applications (IDNA)" 154 | optional = false 155 | python-versions = ">=3.6" 156 | files = [ 157 | {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, 158 | {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, 159 | ] 160 | 161 | [package.extras] 162 | all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] 163 | 164 | [[package]] 165 | name = "pyaml" 166 | version = "24.9.0" 167 | description = "PyYAML-based module to produce a bit more pretty and readable YAML-serialized data" 168 | optional = false 169 | python-versions = ">=3.8" 170 | files = [ 171 | {file = "pyaml-24.9.0-py3-none-any.whl", hash = "sha256:31080551502f1014852b3c966a96c796adc79b4cf86e165f28ed83455bf19c62"}, 172 | {file = "pyaml-24.9.0.tar.gz", hash = "sha256:e78dee8b0d4fed56bb9fa11a8a7858e6fade1ec70a9a122cee6736efac3e69b5"}, 173 | ] 174 | 175 | [package.dependencies] 176 | PyYAML = "*" 177 | 178 | [package.extras] 179 | anchors = ["unidecode"] 180 | 181 | [[package]] 182 | name = "pywin32" 183 | version = "308" 184 | description = "Python for Window Extensions" 185 | optional = false 186 | python-versions = "*" 187 | files = [ 188 | {file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"}, 189 | {file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"}, 190 | {file = "pywin32-308-cp310-cp310-win_arm64.whl", hash = "sha256:a5ab5381813b40f264fa3495b98af850098f814a25a63589a8e9eb12560f450c"}, 191 | {file = "pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a"}, 192 | {file = "pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b"}, 193 | {file = "pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6"}, 194 | {file = "pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897"}, 195 | {file = "pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47"}, 196 | {file = "pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091"}, 197 | {file = "pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed"}, 198 | {file = "pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4"}, 199 | {file = "pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd"}, 200 | {file = "pywin32-308-cp37-cp37m-win32.whl", hash = "sha256:1f696ab352a2ddd63bd07430080dd598e6369152ea13a25ebcdd2f503a38f1ff"}, 201 | {file = "pywin32-308-cp37-cp37m-win_amd64.whl", hash = "sha256:13dcb914ed4347019fbec6697a01a0aec61019c1046c2b905410d197856326a6"}, 202 | {file = "pywin32-308-cp38-cp38-win32.whl", hash = "sha256:5794e764ebcabf4ff08c555b31bd348c9025929371763b2183172ff4708152f0"}, 203 | {file = "pywin32-308-cp38-cp38-win_amd64.whl", hash = "sha256:3b92622e29d651c6b783e368ba7d6722b1634b8e70bd376fd7610fe1992e19de"}, 204 | {file = "pywin32-308-cp39-cp39-win32.whl", hash = "sha256:7873ca4dc60ab3287919881a7d4f88baee4a6e639aa6962de25a98ba6b193341"}, 205 | {file = "pywin32-308-cp39-cp39-win_amd64.whl", hash = "sha256:71b3322d949b4cc20776436a9c9ba0eeedcbc9c650daa536df63f0ff111bb920"}, 206 | ] 207 | 208 | [[package]] 209 | name = "pyyaml" 210 | version = "6.0.2" 211 | description = "YAML parser and emitter for Python" 212 | optional = false 213 | python-versions = ">=3.8" 214 | files = [ 215 | {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, 216 | {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, 217 | {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, 218 | {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, 219 | {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, 220 | {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, 221 | {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, 222 | {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, 223 | {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, 224 | {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, 225 | {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, 226 | {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, 227 | {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, 228 | {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, 229 | {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, 230 | {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, 231 | {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, 232 | {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, 233 | {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, 234 | {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, 235 | {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, 236 | {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, 237 | {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, 238 | {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, 239 | {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, 240 | {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, 241 | {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, 242 | {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, 243 | {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, 244 | {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, 245 | {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, 246 | {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, 247 | {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, 248 | {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, 249 | {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, 250 | {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, 251 | {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, 252 | {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, 253 | {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, 254 | {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, 255 | {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, 256 | {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, 257 | {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, 258 | {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, 259 | {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, 260 | {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, 261 | {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, 262 | {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, 263 | {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, 264 | {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, 265 | {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, 266 | {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, 267 | {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, 268 | ] 269 | 270 | [[package]] 271 | name = "requests" 272 | version = "2.32.3" 273 | description = "Python HTTP for Humans." 274 | optional = false 275 | python-versions = ">=3.8" 276 | files = [ 277 | {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, 278 | {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, 279 | ] 280 | 281 | [package.dependencies] 282 | certifi = ">=2017.4.17" 283 | charset-normalizer = ">=2,<4" 284 | idna = ">=2.5,<4" 285 | urllib3 = ">=1.21.1,<3" 286 | 287 | [package.extras] 288 | socks = ["PySocks (>=1.5.6,!=1.5.7)"] 289 | use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] 290 | 291 | [[package]] 292 | name = "urllib3" 293 | version = "2.2.3" 294 | description = "HTTP library with thread-safe connection pooling, file post, and more." 295 | optional = false 296 | python-versions = ">=3.8" 297 | files = [ 298 | {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, 299 | {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, 300 | ] 301 | 302 | [package.extras] 303 | brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] 304 | h2 = ["h2 (>=4,<5)"] 305 | socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] 306 | zstd = ["zstandard (>=0.18.0)"] 307 | 308 | [metadata] 309 | lock-version = "2.0" 310 | python-versions = ">=3.8" 311 | content-hash = "9fcebd0faade00ce36ae6f306ab2b23521a080299c97e62cc409a5472de8d8f7" 312 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "docker-autocompose" 3 | version = "1.3.0" 4 | description = "Generate a docker-compose yaml definition from a running container" 5 | authors = ["Red5d"] 6 | keywords = ["docker", "yaml", "container"] 7 | license = "GPLv2" 8 | classifiers = [ 9 | "Development Status :: 5 - Production/Stable", 10 | "Environment :: Console", 11 | "Intended Audience :: System Administrators", 12 | "License :: OSI Approved :: GNU General Public License v2 (GPLv2)", 13 | "Operating System :: POSIX :: Linux", 14 | "Programming Language :: Python :: 3 :: Only", 15 | "Programming Language :: Python :: 3.8", 16 | "Programming Language :: Python :: 3.9", 17 | "Programming Language :: Python :: 3.10", 18 | "Programming Language :: Python :: 3.11", 19 | "Programming Language :: Python :: 3.12", 20 | "Topic :: Utilities" 21 | ] 22 | homepage = "https://github.com/Red5d/docker-autocompose" 23 | documentation = "https://github.com/Red5d/docker-autocompose/blob/master/README.md" 24 | repository = "https://github.com/Red5d/docker-autocompose.git" 25 | readme = "README.md" 26 | packages = [ 27 | { include = "src" } 28 | ] 29 | 30 | [tool.poetry.dependencies] 31 | # see https://python-poetry.org/docs/dependency-specification/ for version specifiers 32 | python = ">=3.8" 33 | pyaml = "~24.9.0" 34 | docker = "~7.1.0" 35 | 36 | [tool.poetry.scripts] 37 | autocompose = "src.autocompose:main" 38 | 39 | [build-system] 40 | requires = ["poetry-core"] 41 | build-backend = "poetry.core.masonry.api" 42 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Red5d/docker-autocompose/6c70d7c75f98105e73f3b7d0998013f592d08387/src/__init__.py -------------------------------------------------------------------------------- /src/autocompose.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | import argparse 3 | import datetime 4 | import re 5 | import sys 6 | 7 | from collections import OrderedDict 8 | 9 | import docker 10 | import pyaml 11 | 12 | pyaml.add_representer(bool,lambda s,o: s.represent_scalar('tag:yaml.org,2002:bool',['false','true'][o])) 13 | IGNORE_VALUES = [None, "", [], "null", {}, "default", 0, ",", "no"] 14 | 15 | 16 | def shell_escape_string(input_string): 17 | # Currently known issues: 18 | # - Basic Auth strings (e.g. set via Træfik labels) contain $ characters, which must be doubled. See https://stackoverflow.com/a/40621373/5885325 19 | replaced_string = input_string 20 | for substitution in ( 21 | ("$", "$$"), 22 | ): 23 | replaced_string = replaced_string.replace(substitution[0], substitution[1]) 24 | return replaced_string 25 | 26 | 27 | def list_container_names(): 28 | c = docker.from_env() 29 | return [container.name for container in c.containers.list(all=True)] 30 | 31 | 32 | def list_network_names(): 33 | c = docker.from_env() 34 | return [network.name for network in c.networks.list()] 35 | 36 | 37 | def generate_network_info(): 38 | networks = {} 39 | 40 | for network_name in list_network_names(): 41 | connection = docker.from_env() 42 | network_attributes = connection.networks.get(network_name).attrs 43 | 44 | values = { 45 | "name": network_attributes.get("Name"), 46 | "scope": network_attributes.get("Scope", "local"), 47 | "driver": network_attributes.get("Driver", None), 48 | "enable_ipv6": network_attributes.get("EnableIPv6", False), 49 | "internal": network_attributes.get("Internal", False), 50 | "ipam": { 51 | "driver": network_attributes.get("IPAM", {}).get("Driver", "default"), 52 | "config": [ 53 | {key.lower(): value for key, value in config.items()} 54 | for config in network_attributes.get("IPAM", {}).get("Config", []) 55 | ], 56 | }, 57 | } 58 | 59 | networks[network_name] = {key: value for key, value in values.items()} 60 | 61 | return networks 62 | 63 | 64 | def main(): 65 | parser = argparse.ArgumentParser( 66 | description="Generate docker-compose yaml definition from running container.", 67 | ) 68 | parser.add_argument( 69 | "-a", 70 | "--all", 71 | action="store_true", 72 | help="Include all active containers", 73 | ) 74 | parser.add_argument( 75 | "-v", 76 | "--version", 77 | type=int, 78 | default=3, 79 | help="Compose file version (1 or 3)", 80 | ) 81 | parser.add_argument( 82 | "cnames", 83 | nargs="*", 84 | type=str, 85 | help="The name of the container to process.", 86 | ) 87 | parser.add_argument( 88 | "-c", 89 | "--createvolumes", 90 | action="store_true", 91 | help="Create new volumes instead of reusing existing ones", 92 | ) 93 | parser.add_argument( 94 | "-f", 95 | "--filter", 96 | type=str, 97 | help="Filter containers by regex", 98 | ) 99 | args = parser.parse_args() 100 | 101 | container_names = args.cnames 102 | 103 | if args.all: 104 | container_names.extend(list_container_names()) 105 | 106 | if args.filter: 107 | cfilter = re.compile(args.filter) 108 | container_names = [c for c in container_names if cfilter.search(c)] 109 | 110 | struct = {} 111 | networks = {} 112 | volumes = {} 113 | containers = {} 114 | 115 | for cname in container_names: 116 | cfile, c_networks, c_volumes = generate(cname, createvolumes=args.createvolumes) 117 | 118 | struct.update(cfile) 119 | 120 | if not c_networks == None: 121 | networks.update(c_networks) 122 | if not c_volumes == None: 123 | volumes.update(c_volumes) 124 | 125 | # moving the networks = None statements outside of the for loop. Otherwise any container could reset it. 126 | if len(networks) == 0: 127 | networks = None 128 | if len(volumes) == 0: 129 | volumes = None 130 | 131 | if args.all: 132 | host_networks = generate_network_info() 133 | networks = host_networks 134 | 135 | render(struct, args, networks, volumes) 136 | 137 | 138 | def render(struct, args, networks, volumes): 139 | # Render yaml file 140 | if args.version == 1: 141 | pyaml.p(OrderedDict(struct)) 142 | else: 143 | ans = {"version": '3.6', "services": struct} 144 | 145 | if networks is not None: 146 | ans["networks"] = networks 147 | 148 | if volumes is not None: 149 | ans["volumes"] = volumes 150 | 151 | pyaml.p(OrderedDict(ans), string_val_style='"') 152 | 153 | 154 | def generate(cname, createvolumes=False): 155 | c = docker.from_env() 156 | 157 | try: 158 | cid = [x.short_id for x in c.containers.list(all=True) if cname == x.name or x.short_id in cname][0] 159 | except IndexError: 160 | print("That container is not available.", file=sys.stderr) 161 | sys.exit(1) 162 | 163 | cattrs = c.containers.get(cid).attrs 164 | 165 | # Build yaml dict structure 166 | 167 | cfile = {} 168 | cfile[cattrs.get("Name")[1:]] = {} 169 | ct = cfile[cattrs.get("Name")[1:]] 170 | 171 | default_networks = ["bridge", "host", "none"] 172 | 173 | values = { 174 | "cap_drop": cattrs.get("HostConfig", {}).get("CapDrop", None), 175 | "cgroup_parent": cattrs.get("HostConfig", {}).get("CgroupParent", None), 176 | "container_name": cattrs.get("Name")[1:], 177 | "devices": [], 178 | "dns": cattrs.get("HostConfig", {}).get("Dns", None), 179 | "dns_search": cattrs.get("HostConfig", {}).get("DnsSearch", None), 180 | "environment": cattrs.get("Config", {}).get("Env", None), 181 | "extra_hosts": cattrs.get("HostConfig", {}).get("ExtraHosts", None), 182 | "image": cattrs.get("Config", {}).get("Image", None), 183 | "labels": cattrs.get("Config", {}).get("Labels", {}), 184 | "links": cattrs.get("HostConfig", {}).get("Links"), 185 | #'log_driver': cattrs.get('HostConfig']['LogConfig']['Type'], 186 | #'log_opt': cattrs.get('HostConfig']['LogConfig']['Config'], 187 | "logging": { 188 | "driver": cattrs.get("HostConfig", {}).get("LogConfig", {}).get("Type", None), 189 | "options": cattrs.get("HostConfig", {}).get("LogConfig", {}).get("Config", None), 190 | }, 191 | "networks": { 192 | x for x in cattrs.get("NetworkSettings", {}).get("Networks", {}).keys() if x not in default_networks 193 | }, 194 | "security_opt": cattrs.get("HostConfig", {}).get("SecurityOpt"), 195 | "ulimits": cattrs.get("HostConfig", {}).get("Ulimits"), 196 | # the line below would not handle type bind 197 | # 'volumes': [f'{m["Name"]}:{m["Destination"]}' for m in cattrs.get('Mounts'] if m['Type'] == 'volume'], 198 | "mounts": cattrs.get("Mounts"), # this could be moved outside of the dict. will only use it for generate 199 | "volume_driver": cattrs.get("HostConfig", {}).get("VolumeDriver", None), 200 | "volumes_from": cattrs.get("HostConfig", {}).get("VolumesFrom", None), 201 | "entrypoint": cattrs.get("Config", {}).get("Entrypoint", None), 202 | "user": cattrs.get("Config", {}).get("User", None), 203 | "working_dir": cattrs.get("Config", {}).get("WorkingDir", None), 204 | "domainname": cattrs.get("Config", {}).get("Domainname", None), 205 | "hostname": cattrs.get("Config", {}).get("Hostname", None), 206 | "ipc": cattrs.get("HostConfig", {}).get("IpcMode", None), 207 | "mac_address": cattrs.get("NetworkSettings", {}).get("MacAddress", None), 208 | "privileged": cattrs.get("HostConfig", {}).get("Privileged", None), 209 | "restart": cattrs.get("HostConfig", {}).get("RestartPolicy", {}).get("Name", None), 210 | "read_only": cattrs.get("HostConfig", {}).get("ReadonlyRootfs", None), 211 | "stdin_open": cattrs.get("Config", {}).get("OpenStdin", None), 212 | "tty": cattrs.get("Config", {}).get("Tty", None), 213 | } 214 | 215 | # Populate devices key if device values are present 216 | if cattrs.get("HostConfig", {}).get("Devices"): 217 | values["devices"] = [ 218 | x["PathOnHost"] + ":" + x["PathInContainer"] for x in cattrs.get("HostConfig", {}).get("Devices") 219 | ] 220 | 221 | networks = {} 222 | if values["networks"] == set(): 223 | del values["networks"] 224 | 225 | if len(cattrs.get("NetworkSettings", {}).get("Networks", {}).keys()) > 0: 226 | assumed_default_network = list(cattrs.get("NetworkSettings", {}).get("Networks", {}).keys())[0] 227 | values["network_mode"] = assumed_default_network 228 | networks = None 229 | else: 230 | networklist = c.networks.list() 231 | for network in networklist: 232 | if network.attrs["Name"] in values["networks"]: 233 | networks[network.attrs["Name"]] = { 234 | "external": (not network.attrs["Internal"]), 235 | "name": network.attrs["Name"], 236 | } 237 | # volumes = {} 238 | # if values['volumes'] is not None: 239 | # for volume in values['volumes']: 240 | # volume_name = volume.split(':')[0] 241 | # volumes[volume_name] = {'external': True} 242 | # else: 243 | # volumes = None 244 | 245 | # handles both the returned values['volumes'] (in c_file) and volumes for both, the bind and volume types 246 | # also includes the read only option 247 | volumes = {} 248 | mountpoints = [] 249 | if values["mounts"] is not None: 250 | for mount in values["mounts"]: 251 | destination = mount["Destination"] 252 | if not mount["RW"]: 253 | destination = destination + ":ro" 254 | if mount["Type"] == "volume": 255 | mountpoints.append(mount["Name"] + ":" + destination) 256 | if not createvolumes: 257 | volumes[mount["Name"]] = { 258 | "external": True 259 | } # to reuse an existing volume ... better to make that a choice? (cli argument) 260 | elif mount["Type"] == "bind": 261 | mountpoints.append(mount["Source"] + ":" + destination) 262 | values["volumes"] = sorted(mountpoints) 263 | if len(volumes) == 0: 264 | volumes = None 265 | values["mounts"] = None # remove this temporary data from the returned data 266 | 267 | # Check for command and add it if present. 268 | if cattrs.get("Config", {}).get("Cmd") is not None: 269 | values["command"] = cattrs.get("Config", {}).get("Cmd") 270 | 271 | # Check for exposed/bound ports and add them if needed. 272 | try: 273 | expose_value = list(cattrs.get("Config", {}).get("ExposedPorts", {}).keys()) 274 | ports_value = [ 275 | cattrs.get("HostConfig", {}).get("PortBindings", {})[key][0]["HostIp"] 276 | + ":" 277 | + cattrs.get("HostConfig", {}).get("PortBindings", {})[key][0]["HostPort"] 278 | + ":" 279 | + key 280 | for key in cattrs.get("HostConfig", {}).get("PortBindings") 281 | ] 282 | 283 | # If bound ports found, don't use the 'expose' value. 284 | if ports_value not in IGNORE_VALUES: 285 | for index, port in enumerate(ports_value): 286 | if port[0] == ":": 287 | ports_value[index] = port[1:] 288 | 289 | values["ports"] = ports_value 290 | else: 291 | values["expose"] = expose_value 292 | 293 | except (KeyError, TypeError): 294 | # No ports exposed/bound. Continue without them. 295 | ports = None 296 | 297 | # fixup strings in labels and env 298 | if values["labels"] is not None: 299 | for label_key, label_value in values["labels"].items(): 300 | values["labels"][label_key] = shell_escape_string(label_value) 301 | if values["environment"] is not None: 302 | for idx, env_variable in enumerate(values["environment"]): 303 | values["environment"][idx] = shell_escape_string(env_variable) 304 | 305 | # Iterate through values to finish building yaml dict. 306 | for key in values: 307 | value = values[key] 308 | if value not in IGNORE_VALUES: 309 | ct[key] = value 310 | 311 | return cfile, networks, volumes 312 | 313 | 314 | if __name__ == "__main__": 315 | main() 316 | --------------------------------------------------------------------------------