├── .circleci
└── config.yml
├── .docs
├── Makefile
├── apidoc.sh
├── changelog.md
├── conf.py
├── index.rst
└── source
│ ├── modules.rst
│ ├── scompose.client.rst
│ ├── scompose.logger.rst
│ ├── scompose.project.rst
│ ├── scompose.rst
│ ├── scompose.templates.rst
│ ├── scompose.tests.rst
│ ├── scompose.tests.testdata.rst
│ └── scompose.utils.rst
├── .github
├── FUNDING.yml
├── dev-requirements.txt
└── workflows
│ └── main.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .pylintrc
├── CHANGELOG.md
├── CITATION.cff
├── LICENSE
├── MANIFEST.in
├── README.md
├── docs
├── .nojekyll
├── README.md
├── _coverpage.md
├── api
│ ├── _sources
│ │ ├── changelog.md.txt
│ │ ├── index.rst.txt
│ │ └── source
│ │ │ ├── modules.rst.txt
│ │ │ ├── scompose.client.rst.txt
│ │ │ ├── scompose.logger.rst.txt
│ │ │ ├── scompose.project.rst.txt
│ │ │ ├── scompose.rst.txt
│ │ │ ├── scompose.templates.rst.txt
│ │ │ ├── scompose.tests.rst.txt
│ │ │ ├── scompose.tests.testdata.rst.txt
│ │ │ └── scompose.utils.rst.txt
│ ├── assets
│ │ ├── basic.css
│ │ ├── css
│ │ │ ├── badge_only.css
│ │ │ ├── fonts
│ │ │ │ ├── Roboto-Slab-Bold.woff
│ │ │ │ ├── Roboto-Slab-Bold.woff2
│ │ │ │ ├── Roboto-Slab-Regular.woff
│ │ │ │ ├── Roboto-Slab-Regular.woff2
│ │ │ │ ├── fontawesome-webfont.eot
│ │ │ │ ├── fontawesome-webfont.svg
│ │ │ │ ├── fontawesome-webfont.ttf
│ │ │ │ ├── fontawesome-webfont.woff
│ │ │ │ ├── fontawesome-webfont.woff2
│ │ │ │ ├── lato-bold-italic.woff
│ │ │ │ ├── lato-bold-italic.woff2
│ │ │ │ ├── lato-bold.woff
│ │ │ │ ├── lato-bold.woff2
│ │ │ │ ├── lato-normal-italic.woff
│ │ │ │ ├── lato-normal-italic.woff2
│ │ │ │ ├── lato-normal.woff
│ │ │ │ └── lato-normal.woff2
│ │ │ └── theme.css
│ │ ├── doctools.js
│ │ ├── documentation_options.js
│ │ ├── file.png
│ │ ├── jquery-3.5.1.js
│ │ ├── jquery.js
│ │ ├── js
│ │ │ ├── badge_only.js
│ │ │ ├── html5shiv-printshiv.min.js
│ │ │ ├── html5shiv.min.js
│ │ │ └── theme.js
│ │ ├── language_data.js
│ │ ├── minus.png
│ │ ├── plus.png
│ │ ├── pygments.css
│ │ ├── searchtools.js
│ │ ├── underscore-1.13.1.js
│ │ └── underscore.js
│ ├── changelog.html
│ ├── genindex.html
│ ├── index.html
│ ├── modules
│ │ ├── index.html
│ │ └── scompose
│ │ │ ├── client.html
│ │ │ ├── client
│ │ │ ├── build.html
│ │ │ ├── config.html
│ │ │ ├── create.html
│ │ │ ├── down.html
│ │ │ ├── exec.html
│ │ │ ├── logs.html
│ │ │ ├── ps.html
│ │ │ ├── restart.html
│ │ │ ├── shell.html
│ │ │ └── up.html
│ │ │ ├── logger
│ │ │ ├── message.html
│ │ │ └── progress.html
│ │ │ ├── project
│ │ │ ├── instance.html
│ │ │ └── project.html
│ │ │ ├── templates.html
│ │ │ └── utils.html
│ ├── objects.inv
│ ├── py-modindex.html
│ ├── search.html
│ ├── searchindex.js
│ └── source
│ │ ├── modules.html
│ │ ├── scompose.client.html
│ │ ├── scompose.html
│ │ ├── scompose.logger.html
│ │ ├── scompose.project.html
│ │ ├── scompose.templates.html
│ │ ├── scompose.tests.html
│ │ ├── scompose.tests.testdata.html
│ │ └── scompose.utils.html
├── commands.md
├── img
│ ├── content.png
│ ├── scompose.png
│ ├── scompose.xcf
│ └── upload.png
├── index.html
└── spec
│ ├── README.md
│ ├── spec-1.0.md
│ └── spec-2.0.md
├── paper
├── paper.bib
├── paper.md
└── singularity-compose.png
├── pyproject.toml
├── scompose
├── __init__.py
├── client
│ ├── __init__.py
│ ├── build.py
│ ├── check.py
│ ├── config.py
│ ├── create.py
│ ├── down.py
│ ├── exec.py
│ ├── logs.py
│ ├── ps.py
│ ├── restart.py
│ ├── run.py
│ ├── shell.py
│ └── up.py
├── config
│ ├── __init__.py
│ └── schema.py
├── logger
│ ├── __init__.py
│ ├── message.py
│ └── progress.py
├── project
│ ├── __init__.py
│ ├── instance.py
│ └── project.py
├── templates
│ ├── __init__.py
│ ├── hosts
│ └── resolv.conf
├── tests
│ ├── __init__.py
│ ├── configs
│ │ ├── cmd_args
│ │ │ ├── Singularity
│ │ │ └── singularity-compose.yml
│ │ ├── config_merge
│ │ │ ├── singularity-compose-1.yml
│ │ │ └── singularity-compose-2.yml
│ │ ├── depends_on
│ │ │ ├── Singularity.first
│ │ │ ├── Singularity.second
│ │ │ ├── Singularity.third
│ │ │ └── singularity-compose.yml
│ │ └── wrong_depends_on
│ │ │ ├── Singularity.first
│ │ │ ├── Singularity.second
│ │ │ ├── Singularity.third
│ │ │ └── singularity-compose.yml
│ ├── test_client.py
│ ├── test_command_args.py
│ ├── test_config.py
│ ├── test_depends_on.py
│ └── test_utils.py
├── utils
│ └── __init__.py
└── version.py
├── setup.cfg
└── setup.py
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2.1
2 |
3 | # https://circleci.com/orbs/registry/orb/singularity/singularity
4 | # defaults to golang 1.17.1 and singularity 3.8.2
5 | orbs:
6 | singularity: singularity/singularity@1.0.11
7 |
8 | ################################################################################
9 | # Workflows
10 | ################################################################################
11 |
12 | workflows:
13 | version: 2
14 | test:
15 | jobs:
16 | - run-scompose-ci-tests:
17 | filters:
18 | branches:
19 | ignore: master
20 |
21 | executors:
22 | ubuntu-machine:
23 | machine:
24 | image: ubuntu-2004:202107-02
25 |
26 | ################################################################################
27 | # Functions
28 | ################################################################################
29 |
30 | install_scompose: &install_scompose
31 | name: Install Singularity Compose
32 | command: |
33 | cd ~/repo
34 | pip install .[all]
35 |
36 | test_scompose: &test_scompose
37 | name: Test Singularity Compose
38 | command: |
39 | cd ~/repo
40 | pip install .[all]
41 | pytest -sv scompose/tests/test_depends_on.py
42 | pytest -sv scompose/tests/test_client.py
43 | pytest -sv scompose/tests/test_utils.py
44 | pytest -sv scompose/tests/test_command_args.py
45 | pytest -sv scompose/tests/test_config.py
46 |
47 | install_dependencies: &install_dependencies
48 | name: Install Python dependencies
49 | command: |
50 | PYTHON_VERSION=3
51 | CONDA_PATH="$HOME/conda/Python${PYTHON_VERSION}"
52 | echo 'export PATH="'"$CONDA_PATH"'/bin:$PATH"' >> "$BASH_ENV"
53 | source "$BASH_ENV"
54 | if [ ! -d "$CONDA_PATH" ]; then
55 | CONDA_SCRIPT=Miniconda${PYTHON_VERSION}-latest-Linux-x86_64.sh
56 | wget https://repo.anaconda.com/miniconda/$CONDA_SCRIPT
57 | /bin/bash $CONDA_SCRIPT -b -p $CONDA_PATH
58 | else
59 | echo "Miniconda is already installed, continuing to build."
60 | fi
61 | python --version
62 | [ $(python -c'import sys;print(sys.version_info.major)') -eq $PYTHON_VERSION ]
63 | pip install --upgrade pytest setuptools
64 |
65 | ################################################################################
66 | # Jobs
67 | ################################################################################
68 |
69 | jobs:
70 | run-scompose-ci-tests:
71 | executor: "ubuntu-machine"
72 | working_directory: ~/repo
73 | steps:
74 | - checkout
75 | - restore_cache:
76 | keys: v3-dependencies
77 | - run: *install_dependencies
78 | - singularity/install-go
79 | - singularity/debian-install-3:
80 | singularity-version: 3.8.3
81 | - save_cache:
82 | paths:
83 | - ~/conda
84 | key: v3-dependencies
85 | - run: *install_scompose
86 | - run: *test_scompose
87 |
--------------------------------------------------------------------------------
/.docs/apidoc.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # If the modules changed, the content of "source" should be backed up and
3 | # new files generated (to update) by doing:
4 | #
5 | # sphinx-apidoc -o source/ ../scompose
6 |
7 | HERE="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
8 | BASE=$(dirname $HERE)
9 | cd $HERE
10 | cd $BASE && python setup.py install && cd $HERE && make html
11 | rm -rf $BASE/docs/api
12 |
13 | # Create new folders
14 | mkdir -p $BASE/docs/api
15 |
16 | # Rename folders
17 | find $HERE/_build/html -exec sed -i -e 's/_static/assets/g' {} \;
18 | find $HERE/_build/html -exec sed -i -e 's/_modules/modules/g' {} \;
19 |
20 | # Copy to new locations
21 | mv $HERE/_build/html/_static $BASE/docs/api/assets
22 | mv $HERE/_build/html/_modules $BASE/docs/api/modules
23 | cp -R $HERE/_build/html/* $BASE/docs/api
24 |
--------------------------------------------------------------------------------
/.docs/changelog.md:
--------------------------------------------------------------------------------
1 | ../CHANGELOG.md
2 |
--------------------------------------------------------------------------------
/.docs/index.rst:
--------------------------------------------------------------------------------
1 | Welcome to Singularity Compose API's documentation!
2 | ===================================================
3 |
4 | Singularity Compose is an orchestration tool for Singularity instances.
5 |
6 | Contents:
7 |
8 | .. toctree::
9 | :maxdepth: 3
10 |
11 | source/scompose.rst
12 | changelog.md
13 |
14 |
15 | Indices and tables
16 | ------------------
17 |
18 | * :ref:`modindex`
19 |
--------------------------------------------------------------------------------
/.docs/source/modules.rst:
--------------------------------------------------------------------------------
1 | singularity-compose
2 | ===================
3 |
4 | .. toctree::
5 | :maxdepth: 4
6 |
7 | scompose
8 |
--------------------------------------------------------------------------------
/.docs/source/scompose.client.rst:
--------------------------------------------------------------------------------
1 | scompose.client package
2 | =======================
3 |
4 | Submodules
5 | ----------
6 |
7 | scompose.client.build module
8 | ----------------------------
9 |
10 | .. automodule:: scompose.client.build
11 | :members:
12 | :undoc-members:
13 | :show-inheritance:
14 |
15 | scompose.client.config module
16 | -----------------------------
17 |
18 | .. automodule:: scompose.client.config
19 | :members:
20 | :undoc-members:
21 | :show-inheritance:
22 |
23 | scompose.client.create module
24 | -----------------------------
25 |
26 | .. automodule:: scompose.client.create
27 | :members:
28 | :undoc-members:
29 | :show-inheritance:
30 |
31 | scompose.client.down module
32 | ---------------------------
33 |
34 | .. automodule:: scompose.client.down
35 | :members:
36 | :undoc-members:
37 | :show-inheritance:
38 |
39 | scompose.client.exec module
40 | ---------------------------
41 |
42 | .. automodule:: scompose.client.exec
43 | :members:
44 | :undoc-members:
45 | :show-inheritance:
46 |
47 | scompose.client.logs module
48 | ---------------------------
49 |
50 | .. automodule:: scompose.client.logs
51 | :members:
52 | :undoc-members:
53 | :show-inheritance:
54 |
55 | scompose.client.ps module
56 | -------------------------
57 |
58 | .. automodule:: scompose.client.ps
59 | :members:
60 | :undoc-members:
61 | :show-inheritance:
62 |
63 | scompose.client.restart module
64 | ------------------------------
65 |
66 | .. automodule:: scompose.client.restart
67 | :members:
68 | :undoc-members:
69 | :show-inheritance:
70 |
71 | scompose.client.shell module
72 | ----------------------------
73 |
74 | .. automodule:: scompose.client.shell
75 | :members:
76 | :undoc-members:
77 | :show-inheritance:
78 |
79 | scompose.client.up module
80 | -------------------------
81 |
82 | .. automodule:: scompose.client.up
83 | :members:
84 | :undoc-members:
85 | :show-inheritance:
86 |
87 |
88 | Module contents
89 | ---------------
90 |
91 | .. automodule:: scompose.client
92 | :members:
93 | :undoc-members:
94 | :show-inheritance:
95 |
--------------------------------------------------------------------------------
/.docs/source/scompose.logger.rst:
--------------------------------------------------------------------------------
1 | scompose.logger package
2 | =======================
3 |
4 | Submodules
5 | ----------
6 |
7 | scompose.logger.message module
8 | ------------------------------
9 |
10 | .. automodule:: scompose.logger.message
11 | :members:
12 | :undoc-members:
13 | :show-inheritance:
14 |
15 | scompose.logger.progress module
16 | -------------------------------
17 |
18 | .. automodule:: scompose.logger.progress
19 | :members:
20 | :undoc-members:
21 | :show-inheritance:
22 |
23 |
24 | Module contents
25 | ---------------
26 |
27 | .. automodule:: scompose.logger
28 | :members:
29 | :undoc-members:
30 | :show-inheritance:
31 |
--------------------------------------------------------------------------------
/.docs/source/scompose.project.rst:
--------------------------------------------------------------------------------
1 | scompose.project package
2 | ========================
3 |
4 | Submodules
5 | ----------
6 |
7 | scompose.project.instance module
8 | --------------------------------
9 |
10 | .. automodule:: scompose.project.instance
11 | :members:
12 | :undoc-members:
13 | :show-inheritance:
14 |
15 | scompose.project.project module
16 | -------------------------------
17 |
18 | .. automodule:: scompose.project.project
19 | :members:
20 | :undoc-members:
21 | :show-inheritance:
22 |
23 |
24 | Module contents
25 | ---------------
26 |
27 | .. automodule:: scompose.project
28 | :members:
29 | :undoc-members:
30 | :show-inheritance:
31 |
--------------------------------------------------------------------------------
/.docs/source/scompose.rst:
--------------------------------------------------------------------------------
1 | scompose package
2 | ================
3 |
4 | Subpackages
5 | -----------
6 |
7 | .. toctree::
8 |
9 | scompose.client
10 | scompose.logger
11 | scompose.project
12 | scompose.templates
13 | scompose.tests
14 | scompose.utils
15 |
16 | Submodules
17 | ----------
18 |
19 | scompose.version module
20 | -----------------------
21 |
22 | .. automodule:: scompose.version
23 | :members:
24 | :undoc-members:
25 | :show-inheritance:
26 |
27 |
28 | Module contents
29 | ---------------
30 |
31 | .. automodule:: scompose
32 | :members:
33 | :undoc-members:
34 | :show-inheritance:
35 |
--------------------------------------------------------------------------------
/.docs/source/scompose.templates.rst:
--------------------------------------------------------------------------------
1 | scompose.templates package
2 | ==========================
3 |
4 | Module contents
5 | ---------------
6 |
7 | .. automodule:: scompose.templates
8 | :members:
9 | :undoc-members:
10 | :show-inheritance:
11 |
--------------------------------------------------------------------------------
/.docs/source/scompose.tests.rst:
--------------------------------------------------------------------------------
1 | scompose.tests package
2 | ======================
3 |
4 | Subpackages
5 | -----------
6 |
7 | .. toctree::
8 |
9 | scompose.tests.testdata
10 |
11 | Submodules
12 | ----------
13 |
14 | scompose.tests.test\_client module
15 | ----------------------------------
16 |
17 | .. automodule:: scompose.tests.test_client
18 | :members:
19 | :undoc-members:
20 | :show-inheritance:
21 |
22 | scompose.tests.test\_utils module
23 | ---------------------------------
24 |
25 | .. automodule:: scompose.tests.test_utils
26 | :members:
27 | :undoc-members:
28 | :show-inheritance:
29 |
30 |
31 | Module contents
32 | ---------------
33 |
34 | .. automodule:: scompose.tests
35 | :members:
36 | :undoc-members:
37 | :show-inheritance:
38 |
--------------------------------------------------------------------------------
/.docs/source/scompose.tests.testdata.rst:
--------------------------------------------------------------------------------
1 | scompose.tests.testdata package
2 | ===============================
3 |
4 | Module contents
5 | ---------------
6 |
7 | .. automodule:: scompose.tests.testdata
8 | :members:
9 | :undoc-members:
10 | :show-inheritance:
11 |
--------------------------------------------------------------------------------
/.docs/source/scompose.utils.rst:
--------------------------------------------------------------------------------
1 | scompose.utils package
2 | ======================
3 |
4 | Module contents
5 | ---------------
6 |
7 | .. automodule:: scompose.utils
8 | :members:
9 | :undoc-members:
10 | :show-inheritance:
11 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: vsoch
2 |
--------------------------------------------------------------------------------
/.github/dev-requirements.txt:
--------------------------------------------------------------------------------
1 | pre-commit
2 | black==23.3.0
3 | isort
4 | flake8
5 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: singularity-compose ci
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | pull_request:
8 | branches_ignore: []
9 |
10 | jobs:
11 | tests:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v4
15 | - uses: singularityhub/install-singularity@main
16 | - name: Install dependencies
17 | run: |
18 | python -m pip install --upgrade pip
19 | pip install pytest semver pytest-runner requests
20 | pip install .[all]
21 |
22 | - name: Run unit tests
23 | run: |
24 | which singularity
25 | sudo cp /usr/local/bin/singularity /usr/bin/singularity
26 | pytest -sv scompose/tests/test_depends_on.py
27 | pytest -sv scompose/tests/test_client.py
28 | pytest -sv scompose/tests/test_utils.py
29 | pytest -sv scompose/tests/test_config.py
30 |
31 | formatting:
32 | runs-on: ubuntu-latest
33 | steps:
34 | - uses: actions/checkout@v4
35 |
36 | - name: Setup black environment
37 | run: conda create --quiet --name black
38 |
39 | - name: Check Spelling
40 | uses: crate-ci/typos@7ad296c72fa8265059cc03d1eda562fbdfcd6df2 # v1.9.0
41 | with:
42 | files: ./docs/*.md ./docs/*/*.md ./README.md .docs/*.rst .docs/*/*.rst
43 |
44 | - name: Lint and format Python code
45 | run: |
46 | export PATH="/usr/share/miniconda/bin:$PATH"
47 | source activate black
48 | pip install -r .github/dev-requirements.txt
49 | pre-commit run --all-files
50 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | env
2 | .eggs
3 | .docs/_build
4 | dist
5 | build
6 | __pycache__
7 | singularity_compose.egg-info/
8 | *.sif
9 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | exclude: ".all-contributorsrc"
2 | repos:
3 | - repo: https://github.com/pre-commit/pre-commit-hooks
4 | rev: v4.3.0
5 | hooks:
6 | - id: check-added-large-files
7 | - id: check-case-conflict
8 | - id: check-docstring-first
9 | - id: end-of-file-fixer
10 | - id: trailing-whitespace
11 | - id: mixed-line-ending
12 |
13 | - repo: local
14 | hooks:
15 | - id: black
16 | name: black
17 | language: python
18 | types: [python]
19 | entry: black
20 |
21 | - id: isort
22 | name: isort
23 | args: [--filter-files]
24 | language: python
25 | types: [python]
26 | entry: isort
27 |
28 | - id: flake8
29 | name: flake8
30 | language: python
31 | types: [python]
32 | entry: flake8
33 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # CHANGELOG
2 |
3 | This is a manually generated log to track changes to the repository for each release.
4 | Each section should include general headers such as **Implemented enhancements**
5 | and **Merged pull requests**. Critical items to know are:
6 |
7 | - renamed commands
8 | - deprecated / removed commands
9 | - changed defaults
10 | - backward incompatible changes
11 | - migration guidance
12 | - changed behaviour
13 |
14 | The versions coincide with releases on pypi.
15 |
16 | ## [0.1.x](https://github.com/singularityhub/singularity-compose/tree/master) (0.1.x)
17 | - support for custom network type (0.1.19)
18 | - fix 'bridge' option for 'up' command (0.1.18)
19 | - add support for instance replicas (0.1.17)
20 | - fix check command validation (0.1.16)
21 | - fix a bug triggered when using startoptions in conjunction with network=false (0.1.15)
22 | - bind volumes can handle tilde expansion (0.1.14)
23 | - fix module import used by check command (0.1.13)
24 | - adding jsonschema validation and check command (0.1.12)
25 | - implement configuration override feature
26 | - implement `--preview` argument for the `check` command
27 | - add network->enable option on composer file (0.1.11)
28 | - add network->allocate_ip option on composer file (0.1.10)
29 | - version 2.0 of the spec with added fakeroot network, start, exec, and run options (0.1.0)
30 | - stop option added (equivalent functionality to down)
31 | - spython version 0.1.0 with Singularity 3.x or greater required
32 |
33 | ## [0.0.x](https://github.com/singularityhub/singularity-compose/tree/master) (0.0.x)
34 | - removed check for sudo when adding network flags (0.0.21)
35 | - singularity-compose down supporting timeout (0.0.20)
36 | - command, ability to associate arguments to the instance's startscript (0.0.19)
37 | - depends\_on, check circular dependencies at startup and shutdown in reverse order (0.0.18)
38 | - resolv.conf, etc.hosts generated if needed, network disabled non-sudo users (0.0.17)
39 | - resolv.conf needs to bind by default (0.0.16)
40 | - adding run command (0.0.15)
41 | - ensuring that builds are streamed (0.0.14)
42 | - adding more build options to build as build-flags (0.0.13)
43 | - when not using sudo, need to set --network=none, and catching exec error (0.0.12)
44 | - pyaml version should be for newer kind, and still check for attribute (0.0.11)
45 | - alpha release with simple (single container) working example (0.0.1)
46 | - dummy release (0.0.0)
47 |
--------------------------------------------------------------------------------
/CITATION.cff:
--------------------------------------------------------------------------------
1 | cff-version: 1.1.0
2 | message: "If you use this software, please cite it as below."
3 | authors:
4 | - family-names: Sochat
5 | given-names: Vanessa
6 | orcid: https://orcid.org/0000-0002-4387-3819
7 | title: "Singularity Compose: Orchestration for Singularity Instances"
8 | version: 0.1.0
9 | doi: 10.21105/joss.01578
10 | date-released: 2019-08-26
11 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include README.md LICENSE
2 | recursive-include scompose *
3 | graft scompose
4 | global-exclude __pycache__
5 | global-exclude *.py[co]
6 | global-exclude *.sif
7 | global-exclude *.simg
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Singularity Compose
2 |
3 | [](http://joss.theoj.org/papers/1fc2593b11b5e18df12efb59ed8757a0)
4 | [](https://zenodo.org/badge/latestdoi/188852712)
5 |
6 | This is a simple orchestration library for Singularity containers, akin to
7 | Docker Compose. See the [specification](https://singularityhub.github.io/singularity-compose/#/spec/spec-1.0)
8 | and the [documentation](https://singularityhub.github.io/singularity-compose) for
9 | details, or more examples below.
10 |
11 | ## Examples
12 |
13 | See our [Singularity Compose Examples](https://www.github.com/singularityhub/singularity-compose-examples) repository for
14 | finding or contributing examples for using scompose.
15 |
--------------------------------------------------------------------------------
/docs/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/.nojekyll
--------------------------------------------------------------------------------
/docs/_coverpage.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Singularity Compose docs
4 |
5 | > Singularity Compose for simple container orchestration
6 |
7 | - Definition of services
8 | - Interaction with instances
9 | - Logging and Networking
10 |
11 |
12 |
32 |
33 | [GitHub](https://github.com/singularityhub/singularity-compose)
34 | [Get Started](#singularity-compose)
35 |
--------------------------------------------------------------------------------
/docs/api/_sources/changelog.md.txt:
--------------------------------------------------------------------------------
1 | ../CHANGELOG.md
2 |
--------------------------------------------------------------------------------
/docs/api/_sources/index.rst.txt:
--------------------------------------------------------------------------------
1 | Welcome to Singularity Compose API's documentation!
2 | ===================================================
3 |
4 | Singularity Compose is an orchestration tool for Singularity instances.
5 |
6 | Contents:
7 |
8 | .. toctree::
9 | :maxdepth: 3
10 |
11 | source/scompose.rst
12 | changelog.md
13 |
14 |
15 | Indices and tables
16 | ------------------
17 |
18 | * :ref:`modindex`
19 |
--------------------------------------------------------------------------------
/docs/api/_sources/source/modules.rst.txt:
--------------------------------------------------------------------------------
1 | singularity-compose
2 | ===================
3 |
4 | .. toctree::
5 | :maxdepth: 4
6 |
7 | scompose
8 |
--------------------------------------------------------------------------------
/docs/api/_sources/source/scompose.client.rst.txt:
--------------------------------------------------------------------------------
1 | scompose.client package
2 | =======================
3 |
4 | Submodules
5 | ----------
6 |
7 | scompose.client.build module
8 | ----------------------------
9 |
10 | .. automodule:: scompose.client.build
11 | :members:
12 | :undoc-members:
13 | :show-inheritance:
14 |
15 | scompose.client.config module
16 | -----------------------------
17 |
18 | .. automodule:: scompose.client.config
19 | :members:
20 | :undoc-members:
21 | :show-inheritance:
22 |
23 | scompose.client.create module
24 | -----------------------------
25 |
26 | .. automodule:: scompose.client.create
27 | :members:
28 | :undoc-members:
29 | :show-inheritance:
30 |
31 | scompose.client.down module
32 | ---------------------------
33 |
34 | .. automodule:: scompose.client.down
35 | :members:
36 | :undoc-members:
37 | :show-inheritance:
38 |
39 | scompose.client.exec module
40 | ---------------------------
41 |
42 | .. automodule:: scompose.client.exec
43 | :members:
44 | :undoc-members:
45 | :show-inheritance:
46 |
47 | scompose.client.logs module
48 | ---------------------------
49 |
50 | .. automodule:: scompose.client.logs
51 | :members:
52 | :undoc-members:
53 | :show-inheritance:
54 |
55 | scompose.client.ps module
56 | -------------------------
57 |
58 | .. automodule:: scompose.client.ps
59 | :members:
60 | :undoc-members:
61 | :show-inheritance:
62 |
63 | scompose.client.restart module
64 | ------------------------------
65 |
66 | .. automodule:: scompose.client.restart
67 | :members:
68 | :undoc-members:
69 | :show-inheritance:
70 |
71 | scompose.client.shell module
72 | ----------------------------
73 |
74 | .. automodule:: scompose.client.shell
75 | :members:
76 | :undoc-members:
77 | :show-inheritance:
78 |
79 | scompose.client.up module
80 | -------------------------
81 |
82 | .. automodule:: scompose.client.up
83 | :members:
84 | :undoc-members:
85 | :show-inheritance:
86 |
87 |
88 | Module contents
89 | ---------------
90 |
91 | .. automodule:: scompose.client
92 | :members:
93 | :undoc-members:
94 | :show-inheritance:
95 |
--------------------------------------------------------------------------------
/docs/api/_sources/source/scompose.logger.rst.txt:
--------------------------------------------------------------------------------
1 | scompose.logger package
2 | =======================
3 |
4 | Submodules
5 | ----------
6 |
7 | scompose.logger.message module
8 | ------------------------------
9 |
10 | .. automodule:: scompose.logger.message
11 | :members:
12 | :undoc-members:
13 | :show-inheritance:
14 |
15 | scompose.logger.progress module
16 | -------------------------------
17 |
18 | .. automodule:: scompose.logger.progress
19 | :members:
20 | :undoc-members:
21 | :show-inheritance:
22 |
23 |
24 | Module contents
25 | ---------------
26 |
27 | .. automodule:: scompose.logger
28 | :members:
29 | :undoc-members:
30 | :show-inheritance:
31 |
--------------------------------------------------------------------------------
/docs/api/_sources/source/scompose.project.rst.txt:
--------------------------------------------------------------------------------
1 | scompose.project package
2 | ========================
3 |
4 | Submodules
5 | ----------
6 |
7 | scompose.project.instance module
8 | --------------------------------
9 |
10 | .. automodule:: scompose.project.instance
11 | :members:
12 | :undoc-members:
13 | :show-inheritance:
14 |
15 | scompose.project.project module
16 | -------------------------------
17 |
18 | .. automodule:: scompose.project.project
19 | :members:
20 | :undoc-members:
21 | :show-inheritance:
22 |
23 |
24 | Module contents
25 | ---------------
26 |
27 | .. automodule:: scompose.project
28 | :members:
29 | :undoc-members:
30 | :show-inheritance:
31 |
--------------------------------------------------------------------------------
/docs/api/_sources/source/scompose.rst.txt:
--------------------------------------------------------------------------------
1 | scompose package
2 | ================
3 |
4 | Subpackages
5 | -----------
6 |
7 | .. toctree::
8 |
9 | scompose.client
10 | scompose.logger
11 | scompose.project
12 | scompose.templates
13 | scompose.tests
14 | scompose.utils
15 |
16 | Submodules
17 | ----------
18 |
19 | scompose.version module
20 | -----------------------
21 |
22 | .. automodule:: scompose.version
23 | :members:
24 | :undoc-members:
25 | :show-inheritance:
26 |
27 |
28 | Module contents
29 | ---------------
30 |
31 | .. automodule:: scompose
32 | :members:
33 | :undoc-members:
34 | :show-inheritance:
35 |
--------------------------------------------------------------------------------
/docs/api/_sources/source/scompose.templates.rst.txt:
--------------------------------------------------------------------------------
1 | scompose.templates package
2 | ==========================
3 |
4 | Module contents
5 | ---------------
6 |
7 | .. automodule:: scompose.templates
8 | :members:
9 | :undoc-members:
10 | :show-inheritance:
11 |
--------------------------------------------------------------------------------
/docs/api/_sources/source/scompose.tests.rst.txt:
--------------------------------------------------------------------------------
1 | scompose.tests package
2 | ======================
3 |
4 | Subpackages
5 | -----------
6 |
7 | .. toctree::
8 |
9 | scompose.tests.testdata
10 |
11 | Submodules
12 | ----------
13 |
14 | scompose.tests.test\_client module
15 | ----------------------------------
16 |
17 | .. automodule:: scompose.tests.test_client
18 | :members:
19 | :undoc-members:
20 | :show-inheritance:
21 |
22 | scompose.tests.test\_utils module
23 | ---------------------------------
24 |
25 | .. automodule:: scompose.tests.test_utils
26 | :members:
27 | :undoc-members:
28 | :show-inheritance:
29 |
30 |
31 | Module contents
32 | ---------------
33 |
34 | .. automodule:: scompose.tests
35 | :members:
36 | :undoc-members:
37 | :show-inheritance:
38 |
--------------------------------------------------------------------------------
/docs/api/_sources/source/scompose.tests.testdata.rst.txt:
--------------------------------------------------------------------------------
1 | scompose.tests.testdata package
2 | ===============================
3 |
4 | Module contents
5 | ---------------
6 |
7 | .. automodule:: scompose.tests.testdata
8 | :members:
9 | :undoc-members:
10 | :show-inheritance:
11 |
--------------------------------------------------------------------------------
/docs/api/_sources/source/scompose.utils.rst.txt:
--------------------------------------------------------------------------------
1 | scompose.utils package
2 | ======================
3 |
4 | Module contents
5 | ---------------
6 |
7 | .. automodule:: scompose.utils
8 | :members:
9 | :undoc-members:
10 | :show-inheritance:
11 |
--------------------------------------------------------------------------------
/docs/api/assets/css/badge_only.css:
--------------------------------------------------------------------------------
1 | .fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}
2 |
--------------------------------------------------------------------------------
/docs/api/assets/css/fonts/Roboto-Slab-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/api/assets/css/fonts/Roboto-Slab-Bold.woff
--------------------------------------------------------------------------------
/docs/api/assets/css/fonts/Roboto-Slab-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/api/assets/css/fonts/Roboto-Slab-Bold.woff2
--------------------------------------------------------------------------------
/docs/api/assets/css/fonts/Roboto-Slab-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/api/assets/css/fonts/Roboto-Slab-Regular.woff
--------------------------------------------------------------------------------
/docs/api/assets/css/fonts/Roboto-Slab-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/api/assets/css/fonts/Roboto-Slab-Regular.woff2
--------------------------------------------------------------------------------
/docs/api/assets/css/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/api/assets/css/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/docs/api/assets/css/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/api/assets/css/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/docs/api/assets/css/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/api/assets/css/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/docs/api/assets/css/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/api/assets/css/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/docs/api/assets/css/fonts/lato-bold-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/api/assets/css/fonts/lato-bold-italic.woff
--------------------------------------------------------------------------------
/docs/api/assets/css/fonts/lato-bold-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/api/assets/css/fonts/lato-bold-italic.woff2
--------------------------------------------------------------------------------
/docs/api/assets/css/fonts/lato-bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/api/assets/css/fonts/lato-bold.woff
--------------------------------------------------------------------------------
/docs/api/assets/css/fonts/lato-bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/api/assets/css/fonts/lato-bold.woff2
--------------------------------------------------------------------------------
/docs/api/assets/css/fonts/lato-normal-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/api/assets/css/fonts/lato-normal-italic.woff
--------------------------------------------------------------------------------
/docs/api/assets/css/fonts/lato-normal-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/api/assets/css/fonts/lato-normal-italic.woff2
--------------------------------------------------------------------------------
/docs/api/assets/css/fonts/lato-normal.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/api/assets/css/fonts/lato-normal.woff
--------------------------------------------------------------------------------
/docs/api/assets/css/fonts/lato-normal.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/api/assets/css/fonts/lato-normal.woff2
--------------------------------------------------------------------------------
/docs/api/assets/documentation_options.js:
--------------------------------------------------------------------------------
1 | var DOCUMENTATION_OPTIONS = {
2 | URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
3 | VERSION: '1',
4 | LANGUAGE: 'None',
5 | COLLAPSE_INDEX: false,
6 | BUILDER: 'html',
7 | FILE_SUFFIX: '.html',
8 | LINK_SUFFIX: '.html',
9 | HAS_SOURCE: true,
10 | SOURCELINK_SUFFIX: '.txt',
11 | NAVIGATION_WITH_KEYS: false
12 | };
13 |
--------------------------------------------------------------------------------
/docs/api/assets/file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/api/assets/file.png
--------------------------------------------------------------------------------
/docs/api/assets/js/badge_only.js:
--------------------------------------------------------------------------------
1 | !function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=4)}({4:function(e,t,r){}});
2 |
--------------------------------------------------------------------------------
/docs/api/assets/js/html5shiv-printshiv.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @preserve HTML5 Shiv 3.7.3-pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
3 | */
4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML=" ",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document);
5 |
--------------------------------------------------------------------------------
/docs/api/assets/js/html5shiv.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
3 | */
4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML=" ",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document);
5 |
--------------------------------------------------------------------------------
/docs/api/assets/js/theme.js:
--------------------------------------------------------------------------------
1 | !function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap(""),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(' '),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t
2 |
3 |
4 |
5 |
6 | <no title> — Singularity Compose API 1 documentation
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
47 |
48 |
49 |
50 |
51 | Singularity Compose API
52 |
53 |
54 |
55 |
56 |
66 |
67 |
68 |
69 |
../CHANGELOG.md
70 |
71 |
72 |
73 |
74 |
90 |
91 |
92 |
93 |
94 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/docs/api/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Welcome to Singularity Compose API’s documentation! — Singularity Compose API 1 documentation
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
47 |
48 |
49 |
50 |
51 | Singularity Compose API
52 |
53 |
54 |
55 |
56 |
57 |
58 | »
59 | Welcome to Singularity Compose API’s documentation!
60 |
61 | View page source
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
Welcome to Singularity Compose API’s documentation!
71 |
Singularity Compose is an orchestration tool for Singularity instances.
72 |
Contents:
73 |
92 |
93 |
Indices and tables
94 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
119 |
120 |
121 |
122 |
123 |
128 |
129 |
130 |
131 |
--------------------------------------------------------------------------------
/docs/api/modules/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Overview: module code — Singularity Compose API 1 documentation
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
46 |
47 |
48 |
49 |
50 | Singularity Compose API
51 |
52 |
53 |
54 |
55 |
56 |
57 | »
58 | Overview: module code
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
All modules for which code is available
68 |
86 |
87 |
88 |
89 |
103 |
104 |
105 |
106 |
107 |
112 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/docs/api/modules/scompose/client/build.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | scompose.client.build — Singularity Compose API 1 documentation
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
46 |
47 |
48 |
49 |
50 | Singularity Compose API
51 |
52 |
53 |
54 |
55 |
66 |
67 |
68 |
69 |
Source code for scompose.client.build
70 | """
71 |
72 | Copyright (C) 2019-2021 Vanessa Sochat.
73 |
74 | This Source Code Form is subject to the terms of the
75 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
76 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
77 |
78 |
79 | """
80 |
81 | from scompose.project import Project
82 |
83 |
84 | [docs] def main ( args , parser , extra ):
85 |
"""Build or rebuild containers
86 |
87 |
Containers are built once and then named as <project>_<service>,
88 |
e.g. `folder_db`. If a Singularity recipe changes for a container folder,
89 |
you can run "singularity-compose build" to rebuild it.
90 |
"""
91 |
# Initialize the project
92 |
project = Project (
93 |
filename = args . file , name = args . project_name , env_file = args . env_file
94 |
)
95 |
96 |
# Builds any containers into folders
97 |
project . build ( args . names )
98 |
99 |
100 |
101 |
102 |
116 |
117 |
118 |
119 |
120 |
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/docs/api/modules/scompose/client/config.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | scompose.client.config — Singularity Compose API 1 documentation
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
46 |
47 |
48 |
49 |
50 | Singularity Compose API
51 |
52 |
53 |
54 |
55 |
66 |
67 |
68 |
69 |
Source code for scompose.client.config
70 | """
71 |
72 | Copyright (C) 2019-2021 Vanessa Sochat.
73 |
74 | This Source Code Form is subject to the terms of the
75 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
76 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
77 |
78 |
79 | """
80 |
81 | from scompose.project import Project
82 |
83 |
84 | [docs] def main ( args , parser , extra ):
85 |
"""View or validate a configuration file
86 |
87 |
This comes down to reading in the config to the project, at which
88 |
case it is validated. We then print it for the user.
89 |
"""
90 |
# Initialize the project
91 |
project = Project (
92 |
filename = args . file , name = args . project_name , env_file = args . env_file
93 |
)
94 |
95 |
# Builds any containers into folders
96 |
project . view_config ()
97 |
98 |
99 |
100 |
101 |
115 |
116 |
117 |
118 |
119 |
124 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/docs/api/modules/scompose/client/create.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | scompose.client.create — Singularity Compose API 1 documentation
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
46 |
47 |
48 |
49 |
50 | Singularity Compose API
51 |
52 |
53 |
54 |
55 |
66 |
67 |
68 |
69 |
Source code for scompose.client.create
70 | """
71 |
72 | Copyright (C) 2019-2021 Vanessa Sochat.
73 |
74 | This Source Code Form is subject to the terms of the
75 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
76 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
77 |
78 |
79 | """
80 |
81 | from scompose.project import Project
82 |
83 |
84 | [docs] def main ( args , parser , extra ):
85 |
"""create one or more instances. If they don't exist, build first.
86 |
87 |
This will build and bring up one or more named instances, or if None
88 |
are provided, we create all of them.
89 |
"""
90 |
# Initialize the project
91 |
project = Project (
92 |
filename = args . file , name = args . project_name , env_file = args . env_file
93 |
)
94 |
95 |
# Create instances, and if none specified, create all
96 |
project . create (
97 |
args . names ,
98 |
writable_tmpfs = not args . read_only ,
99 |
bridge = args . bridge ,
100 |
no_resolv = args . no_resolv ,
101 |
)
102 |
103 |
104 |
105 |
106 |
120 |
121 |
122 |
123 |
124 |
129 |
130 |
131 |
132 |
--------------------------------------------------------------------------------
/docs/api/modules/scompose/client/down.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | scompose.client.down — Singularity Compose API 1 documentation
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
46 |
47 |
48 |
49 |
50 | Singularity Compose API
51 |
52 |
53 |
54 |
55 |
66 |
67 |
68 |
69 |
Source code for scompose.client.down
70 | """
71 |
72 | Copyright (C) 2019-2021 Vanessa Sochat.
73 |
74 | This Source Code Form is subject to the terms of the
75 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
76 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
77 |
78 |
79 | """
80 |
81 | from scompose.project import Project
82 |
83 |
84 | [docs] def main ( args , parser , extra ):
85 |
"""bring one or more instances down"""
86 |
# Initialize the project
87 |
project = Project (
88 |
filename = args . file , name = args . project_name , env_file = args . env_file
89 |
)
90 |
91 |
# Create instances, and if none specified, create all
92 |
project . down ( args . names , args . timeout )
93 |
94 |
95 |
96 |
97 |
111 |
112 |
113 |
114 |
115 |
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/docs/api/modules/scompose/client/exec.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | scompose.client.exec — Singularity Compose API 1 documentation
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
46 |
47 |
48 |
49 |
50 | Singularity Compose API
51 |
52 |
53 |
54 |
55 |
66 |
67 |
68 |
69 |
Source code for scompose.client.exec
70 | """
71 |
72 | Copyright (C) 2019-2021 Vanessa Sochat.
73 |
74 | This Source Code Form is subject to the terms of the
75 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
76 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
77 |
78 |
79 | """
80 |
81 | from scompose.project import Project
82 |
83 |
84 | [docs] def main ( args , parser , extra ):
85 |
"""execute a command to an instance."""
86 |
# Initialize the project
87 |
project = Project (
88 |
filename = args . file , name = args . project_name , env_file = args . env_file
89 |
)
90 |
91 |
project . execute ( args . name [ 0 ], extra )
92 |
93 |
94 |
95 |
96 |
110 |
111 |
112 |
113 |
114 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/docs/api/modules/scompose/client/logs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | scompose.client.logs — Singularity Compose API 1 documentation
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
46 |
47 |
48 |
49 |
50 | Singularity Compose API
51 |
52 |
53 |
54 |
55 |
66 |
67 |
68 |
69 |
Source code for scompose.client.logs
70 | """
71 |
72 | Copyright (C) 2019-2021 Vanessa Sochat.
73 |
74 | This Source Code Form is subject to the terms of the
75 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
76 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
77 |
78 |
79 | """
80 |
81 | from scompose.project import Project
82 |
83 |
84 | [docs] def main ( args , parser , extra ):
85 |
"""bring one or more instances down"""
86 |
# Initialize the project
87 |
project = Project (
88 |
filename = args . file , name = args . project_name , env_file = args . env_file
89 |
)
90 |
91 |
if args . clear :
92 |
project . clear_logs ( args . names )
93 |
else :
94 |
project . logs ( args . names , args . tail )
95 |
96 |
97 |
98 |
99 |
113 |
114 |
115 |
116 |
117 |
122 |
123 |
124 |
125 |
--------------------------------------------------------------------------------
/docs/api/modules/scompose/client/ps.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | scompose.client.ps — Singularity Compose API 1 documentation
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
46 |
47 |
48 |
49 |
50 | Singularity Compose API
51 |
52 |
53 |
54 |
55 |
66 |
67 |
68 |
69 |
Source code for scompose.client.ps
70 | """
71 |
72 | Copyright (C) 2019-2021 Vanessa Sochat.
73 |
74 | This Source Code Form is subject to the terms of the
75 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
76 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
77 |
78 |
79 | """
80 |
81 | from scompose.project import Project
82 |
83 |
84 | [docs] def main ( args , parser , extra ):
85 |
"""bring one or more instances down"""
86 |
# Initialize the project
87 |
project = Project (
88 |
filename = args . file , name = args . project_name , env_file = args . env_file
89 |
)
90 |
91 |
# Create instances, and if none specified, create all
92 |
project . ps ()
93 |
94 |
95 |
96 |
97 |
111 |
112 |
113 |
114 |
115 |
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/docs/api/modules/scompose/client/restart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | scompose.client.restart — Singularity Compose API 1 documentation
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
46 |
47 |
48 |
49 |
50 | Singularity Compose API
51 |
52 |
53 |
54 |
55 |
66 |
67 |
68 |
69 |
Source code for scompose.client.restart
70 | """
71 |
72 | Copyright (C) 2019-2021 Vanessa Sochat.
73 |
74 | This Source Code Form is subject to the terms of the
75 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
76 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
77 |
78 |
79 | """
80 |
81 | from scompose.project import Project
82 |
83 |
84 | [docs] def main ( args , parser , extra ):
85 |
"""bring up one or more instances. They must exist.
86 |
87 |
This will build and bring up one or more named instances, or if None
88 |
are provided, we create all of them.
89 |
"""
90 |
# Initialize the project
91 |
project = Project (
92 |
filename = args . file , name = args . project_name , env_file = args . env_file
93 |
)
94 |
95 |
# Create instances, and if none specified, create all
96 |
project . down ( args . names )
97 |
98 |
# Create instances, and if none specified, create all
99 |
project . up (
100 |
args . names ,
101 |
writable_tmpfs = not args . read_only ,
102 |
bridge = args . bridge ,
103 |
no_resolv = args . no_resolv ,
104 |
)
105 |
106 |
107 |
108 |
109 |
123 |
124 |
125 |
126 |
127 |
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/docs/api/modules/scompose/client/shell.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | scompose.client.shell — Singularity Compose API 1 documentation
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
46 |
47 |
48 |
49 |
50 | Singularity Compose API
51 |
52 |
53 |
54 |
55 |
66 |
67 |
68 |
69 |
Source code for scompose.client.shell
70 | """
71 |
72 | Copyright (C) 2019-2021 Vanessa Sochat.
73 |
74 | This Source Code Form is subject to the terms of the
75 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
76 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
77 |
78 | """
79 |
80 | from scompose.project import Project
81 |
82 |
83 | [docs] def main ( args , parser , extra ):
84 |
"""bring one or more instances down"""
85 |
# Initialize the project
86 |
project = Project (
87 |
filename = args . file , name = args . project_name , env_file = args . env_file
88 |
)
89 |
90 |
# Create instances, and if none specified, create all
91 |
project . shell ( args . name [ 0 ])
92 |
93 |
94 |
95 |
96 |
110 |
111 |
112 |
113 |
114 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/docs/api/modules/scompose/client/up.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | scompose.client.up — Singularity Compose API 1 documentation
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
46 |
47 |
48 |
49 |
50 | Singularity Compose API
51 |
52 |
53 |
54 |
55 |
66 |
67 |
68 |
69 |
Source code for scompose.client.up
70 | """
71 |
72 | Copyright (C) 2019-2021 Vanessa Sochat.
73 |
74 | This Source Code Form is subject to the terms of the
75 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
76 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
77 |
78 | """
79 |
80 | from scompose.project import Project
81 |
82 |
83 | [docs] def main ( args , parser , extra ):
84 |
"""bring up one or more instances. They must exist.
85 |
86 |
This will build and bring up one or more named instances, or if None
87 |
are provided, we create all of them.
88 |
"""
89 |
# Initialize the project
90 |
project = Project (
91 |
filename = args . file , name = args . project_name , env_file = args . env_file
92 |
)
93 |
94 |
# Create instances, and if none specified, create all
95 |
project . up (
96 |
args . names ,
97 |
writable_tmpfs = not args . read_only ,
98 |
bridge = args . bridge ,
99 |
no_resolv = args . no_resolv ,
100 |
)
101 |
102 |
103 |
104 |
105 |
119 |
120 |
121 |
122 |
123 |
128 |
129 |
130 |
131 |
--------------------------------------------------------------------------------
/docs/api/modules/scompose/templates.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | scompose.templates — Singularity Compose API 1 documentation
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
46 |
47 |
48 |
49 |
50 | Singularity Compose API
51 |
52 |
53 |
54 |
55 |
56 |
57 | »
58 | Module code »
59 | scompose.templates
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
Source code for scompose.templates
69 | """
70 |
71 | Copyright (C) 2019-2021 Vanessa Sochat.
72 |
73 | This Source Code Form is subject to the terms of the
74 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
75 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
76 |
77 | """
78 |
79 | from scompose.logger import bot
80 | from scompose.utils import get_installdir
81 |
82 | import os
83 |
84 |
85 | [docs] def get_template ( name ):
86 |
"""get a template by name from this directory. If does not exist,
87 |
return None.
88 |
"""
89 |
here = get_installdir ()
90 |
template = os . path . join ( here , "templates" , name )
91 |
if os . path . exists ( template ):
92 |
return template
93 |
bot . warning ( " %s does not exist." % template )
94 |
95 |
96 |
97 |
98 |
112 |
113 |
114 |
115 |
116 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/docs/api/objects.inv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/api/objects.inv
--------------------------------------------------------------------------------
/docs/api/search.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Search — Singularity Compose API 1 documentation
7 |
8 |
9 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
49 |
50 |
51 |
52 |
53 | Singularity Compose API
54 |
55 |
56 |
57 |
58 |
59 |
60 | »
61 | Search
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | Please activate JavaScript to enable the search functionality.
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
99 |
100 |
101 |
102 |
103 |
108 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/docs/api/source/scompose.tests.testdata.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | scompose.tests.testdata package — Singularity Compose API 1 documentation
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
69 |
70 |
71 |
72 |
73 | Singularity Compose API
74 |
75 |
76 |
77 |
78 |
90 |
91 |
92 |
93 |
94 |
scompose.tests.testdata package
95 |
96 |
Module contents
97 |
98 |
99 |
100 |
101 |
102 |
103 |
120 |
121 |
122 |
123 |
124 |
129 |
130 |
131 |
132 |
--------------------------------------------------------------------------------
/docs/img/content.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/img/content.png
--------------------------------------------------------------------------------
/docs/img/scompose.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/img/scompose.png
--------------------------------------------------------------------------------
/docs/img/scompose.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/img/scompose.xcf
--------------------------------------------------------------------------------
/docs/img/upload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/docs/img/upload.png
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Singularity Compose: Container Orchestration
6 |
7 |
8 |
9 |
10 |
21 |
22 |
23 |
24 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/docs/spec/README.md:
--------------------------------------------------------------------------------
1 | # Specifications
2 |
3 | This folder contains specifications for each version of a singularity-compose.yml file.
4 |
5 | - [2.0](spec/spec-2.0.md) is version 2 of the specification with added network, start, exec, and run options. See [the file here](https://github.com/singularityhub/singularity-compose/tree/master/docs/spec/spec-2.0.md). You should use version 0.1.0 or later for this spec.
6 | - [1.0](spec/spec-1.0.md) is version 1 (current) of the under development specification. See [the file here](https://github.com/singularityhub/singularity-compose/tree/master/docs/spec/spec-1.0.md). You should use a version less than 0.1.0 for this version.
7 |
--------------------------------------------------------------------------------
/docs/spec/spec-1.0.md:
--------------------------------------------------------------------------------
1 | # Singularity Compose Version 1.0
2 |
3 | ## Overview
4 |
5 | The main format of the file is yaml. We must define a version and one or more
6 | instances under "instances." Here is a full example for reference.
7 |
8 | ```yaml
9 | version: "1.0"
10 | instances:
11 |
12 | nginx:
13 | build:
14 | context: ./nginx
15 | recipe: Singularity.nginx
16 | volumes:
17 | - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
18 | - ./uwsgi_params.par:/etc/nginx/uwsgi_params.par:ro
19 | volumes_from:
20 | - app
21 | ports:
22 | - "80"
23 |
24 | db:
25 | image: postgres:9.4
26 | volumes:
27 | - db-data:/var/lib/postgresql/data
28 |
29 | app:
30 | build:
31 | context: ./app
32 | volumes:
33 | - .:/code
34 | - ./static:/var/www/static
35 | - ./images:/var/www/images
36 | ports:
37 | - "5000:80"
38 | depends_on:
39 | - nginx
40 | ```
41 |
42 | Each of nginx, uwsgi, and db are instances to be built as containers, and run
43 | as instances.
44 |
45 | ## Networking
46 |
47 | Since Singularity does not (currently) have control over custom networking,
48 | all instance ports are mapped to the host (localhost) and we don't have any
49 | configuration settings to control this (how to handle ports?)
50 |
51 | ## Startscript arguments
52 |
53 | It is possible to use the `command` option to pass arguments to an instance's
54 | startscript.
55 |
56 | The following example shows how to pass the arguments `arg0 arg1 arg2` to the
57 | startscript of instance `app`,
58 |
59 | ```yaml
60 | app:
61 | build:
62 | context: ./app
63 | command: "arg0 arg1 arg2"
64 | ```
65 |
66 | ## Environment
67 |
68 | While Singularity compose doesn't currently have support for an environment
69 | section, it's easy to add custom environments by way of binding an environment
70 | file to the instance! For example:
71 |
72 | ```yaml
73 | app:
74 | build:
75 | context: ./app
76 | volumes:
77 | - ./env_file.sh:/.singularity.d/env/env_file.sh
78 | ```
79 |
80 | Any file that is found in the `.singularity.d/env` folder will be sourced.
81 | For example, you could define or export variables like so:
82 |
83 | ```bash
84 | #!/bin/bash
85 | MYNAME=dinosaur
86 | export MYNAME
87 | ```
88 |
89 | Make sure to export variables.
90 |
91 | ## Instance
92 |
93 | An instance currently must be instantiated from a container built
94 | from a Singularity recipe in a named folder (the example above)
95 | alongside the singularity-compose.yml:
96 |
97 | ```
98 | nginx:
99 | build:
100 | context: ./nginx
101 | recipe: Singularity.nginx
102 | volumes:
103 | - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
104 | - ./uwsgi_params.par:/etc/nginx/uwsgi_params.par:ro
105 | volumes_from:
106 | - uwsgi
107 | ports:
108 | - "80"
109 | ```
110 |
111 | or from a container unique resource identifier (uri) that can be pulled
112 | to a local directory with the same name as the section.
113 |
114 | ```
115 | nginx:
116 | image: docker://vanessa/sregistry_nginx
117 | volumes:
118 | - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
119 | - ./uwsgi_params.par:/etc/nginx/uwsgi_params.par:ro
120 | volumes_from:
121 | - uwsgi
122 | ports:
123 | - "80"
124 | ```
125 |
126 | We build or pull a local container for reproducibility. The first approach,
127 | building from a local file, is recommended as you have full control over
128 | the environment and startscript, and there are likely few containers out in the
129 | wild (and ready to be pulled) that have the correct entry and start scripts
130 | for your application. In the case that you *do* want to pull
131 | a container (and use the existing startscript or entrypoint) you can do that
132 | as follows:
133 |
134 | ```
135 | nginx:
136 | image: docker://vanessa/sregistry_nginx
137 | ...
138 | ```
139 |
140 | Customization of an image (e.g., labels, help, post) is out of
141 | scope for singularity-compose, and you must build from a recipe instead.
142 | The fields for instances are discussed below:
143 |
144 |
145 | ### Fields
146 |
147 | |Name| Description |
148 | |----|-------------|
149 | |name|The name of the instance will be "nginx" unless the user provides a "name"
150 | field (not defined above).|
151 | |build| a section to define how and where to build the base container from.|
152 | |build.context| the folder with the Singularity file (and other relevant files). Must exist.
153 | |build.recipe| the Singularity recipe in the build context folder. It defaults to `Singularity`|
154 | |build.options| a list of one or more options (single strings for boolean, or key value pairs for arguments) to provide to build. This is where you could provide fakeroot.|
155 | |image| is looked for after a build entry. It can be a unique resource identifier, or container binary. |
156 | |volumes| one or more files or files to bind to the instance when it's started.|
157 | |volumes_from| shared volumes that are defined for other instances|
158 | |ports| currently not sure how I'm going to handle this!|
159 | |post| a section of post commands and arguments, run after instance creation |
160 | |post.commands| a list of commands to run (directly or a script) on the host |
161 |
--------------------------------------------------------------------------------
/paper/paper.bib:
--------------------------------------------------------------------------------
1 | @ARTICLE{Kurtzer2017-xj,
2 | title = "Singularity: Scientific containers for mobility of compute",
3 | author = "Kurtzer, Gregory M and Sochat, Vanessa and Bauer, Michael W",
4 | abstract = "Here we present Singularity, software developed to bring
5 | containers and reproducibility to scientific computing. Using
6 | Singularity containers, developers can work in reproducible
7 | environments of their choosing and design, and these complete
8 | environments can easily be copied and executed on other
9 | platforms. Singularity is an open source initiative that
10 | harnesses the expertise of system and software engineers and
11 | researchers alike, and integrates seamlessly into common
12 | workflows for both of these groups. As its primary use case,
13 | Singularity brings mobility of computing to both users and HPC
14 | centers, providing a secure means to capture and distribute
15 | software and compute environments. This ability to create and
16 | deploy reproducible environments across these centers, a
17 | previously unmet need, makes Singularity a game changing
18 | development for computational science.",
19 | journal = "PLoS One",
20 | doi = "10.1371/journal.pone.0177459",
21 | publisher = "Public Library of Science",
22 | volume = 12,
23 | number = 5,
24 | pages = "e0177459",
25 | month = "11~" # may,
26 | year = 2017
27 | }
28 |
29 |
30 | @Software{SingularityCompose,
31 | title = "singularity-compose",
32 | booktitle = "Singularity Compose",
33 | author = "Sochat, Vanessa",
34 | abstract = "orchestration tool for Singularity container instances",
35 | howpublished = "\url{https://singularityhub.github.io/singularity-compose}",
36 | note = "Accessed: 2019-6-24",
37 | date = "2019-06-24"
38 | }
39 |
40 |
41 | @Software{SingularityComposeGithub,
42 | title = "Singularity Compose {Github}",
43 | booktitle = "Singularity Compose {Github}",
44 | author = "Sochat, Vanessa",
45 | abstract = "open source code for singularity-compose",
46 | howpublished = "\url{https://github.com/singularityhub/singularity-compose}",
47 | note = "Accessed: 2019-6-24",
48 | date = "2019-06-24"
49 | }
50 |
51 |
52 |
53 | @Software{DockerCompose,
54 | title = "Docker {Compose}",
55 | booktitle = "Docker Documentation",
56 | author = {{Docker, Inc.}},
57 | abstract = "Introduction and Overview of Compose",
58 | howpublished = "\url{https://docs.docker.com/compose/}",
59 | note = "Accessed: 2019-6-24",
60 | date = "2019-06-24"
61 | }
62 |
63 |
64 | @Software{SingularityComposeExamples,
65 | title = "Singularity Compose Examples",
66 | booktitle = "Singularity Compose Examples",
67 | author = "Sochat, Vanessa",
68 | abstract = "open source examples for singularity-compose",
69 | howpublished = "\url{https://github.com/singularityhub/singularity-compose-examples}",
70 | note = "Accessed: 2019-6-24",
71 | date = "2019-06-24"
72 | }
73 |
74 | @MISC{Merkel2014-da,
75 | title = "Docker: Lightweight {Linux} Containers for Consistent Development
76 | and Deployment",
77 | author = "Merkel, Dirk",
78 | journal = "Linux J.",
79 | publisher = "Belltown Media",
80 | volume = 2014,
81 | number = 239,
82 | month = mar,
83 | year = 2014,
84 | address = "Houston, TX"
85 | }
86 |
87 |
88 | @MISC{Wikipedia_contributors2019-bw,
89 | title = "Kubernetes",
90 | booktitle = "Wikipedia, The Free Encyclopedia",
91 | author = "{Wikipedia contributors}",
92 | abstract = "Kubernetes (commonly stylized as k8s[3]) is an open-source
93 | container-orchestration system for automating application
94 | deployment, scaling, and management.[4] It was originally
95 | designed by Google, and is now maintained by the Cloud Native
96 | Computing Foundation. It aims to provide a ``platform for
97 | automating deployment, scaling, and operations of application
98 | containers across clusters of hosts''.[3] It works with a
99 | range of container tools, including Docker.[5] Many cloud
100 | services offer a Kubernetes-based platform or infrastructure
101 | as a service (PaaS or IaaS) on which Kubernetes can be
102 | deployed as a platform-providing service. Many vendors also
103 | provide their own branded Kubernetes distributions.",
104 | month = jun,
105 | year = 2019,
106 | howpublished = "\url{https://en.wikipedia.org/w/index.php?title=Kubernetes&oldid=903021989}",
107 | note = "Accessed: 2019-6-24"
108 | }
109 |
110 | @MISC{SingularityInstances,
111 | title = "Running Services --- {Singularity} container 3.2 documentation",
112 | author = "{Singularity contributors}",
113 | howpublished = "\url{https://sylabs.io/guides/3.2/user-guide/running_services.html?highlight=instances}",
114 | note = "Accessed: 2019-6-24",
115 | year = 2019
116 | }
117 |
118 |
119 | @MISC{Meyer2019-sd,
120 | title = "Sylabs Slides Singularity Updates Into Its Enterprise Pro
121 | Package",
122 | booktitle = "{SDxCentral}",
123 | author = "Meyer, Dan",
124 | abstract = "Sylabs pushed out an update to its enterprise-focused
125 | SingularityPRO container platform that takes advantage of its
126 | 3.x launch.",
127 | month = apr,
128 | year = 2019,
129 | howpublished = "\url{https://www.sdxcentral.com/articles/news/sylabs-slides-singularity-updates-into-its-enterprise-pro-package/2019/04/}",
130 | note = "Accessed: 2019-6-24"
131 | }
132 |
--------------------------------------------------------------------------------
/paper/singularity-compose.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/paper/singularity-compose.png
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.black]
2 | profile = "black"
3 | exclude = ["^env/"]
4 |
5 | [tool.isort]
6 | profile = "black" # needed for black/isort compatibility
7 | skip = []
8 |
--------------------------------------------------------------------------------
/scompose/__init__.py:
--------------------------------------------------------------------------------
1 | from .version import __version__
2 |
--------------------------------------------------------------------------------
/scompose/client/build.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | Copyright (C) 2019-2024 Vanessa Sochat.
4 |
5 | This Source Code Form is subject to the terms of the
6 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
7 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 |
10 | """
11 |
12 | from scompose.project import Project
13 |
14 |
15 | def main(args, parser, extra):
16 | """Build or rebuild containers
17 |
18 | Containers are built once and then named as _,
19 | e.g. `folder_db`. If a Singularity recipe changes for a container folder,
20 | you can run "singularity-compose build" to rebuild it.
21 | """
22 | # Initialize the project
23 | project = Project(
24 | filename=args.file, name=args.project_name, env_file=args.env_file
25 | )
26 |
27 | # Builds any containers into folders
28 | project.build(args.names)
29 |
--------------------------------------------------------------------------------
/scompose/client/check.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | Copyright (C) 2021-2024 Vanessa Sochat.
4 |
5 | This Source Code Form is subject to the terms of the
6 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
7 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 | """
10 |
11 | import yaml
12 |
13 | from scompose.config import merge_config
14 | from scompose.config.schema import validate_config
15 | from scompose.logger import bot
16 |
17 |
18 | def main(args, parser, extra):
19 | """
20 | Validate compose files for correctness.
21 |
22 | CLI Arguments
23 | ==========
24 | --preview flag to show combined configs.
25 | """
26 |
27 | # validate compose files
28 | for f in args.file:
29 | valid = validate_config(f)
30 | if valid and not args.preview:
31 | bot.info("%s is valid." % f)
32 | elif not valid:
33 | bot.exit("%s is not valid." % f)
34 |
35 | if args.preview:
36 | # preview
37 | config = merge_config(args.file)
38 | print(yaml.dump(config, sort_keys=False))
39 |
--------------------------------------------------------------------------------
/scompose/client/config.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | Copyright (C) 2019-2024 Vanessa Sochat.
4 |
5 | This Source Code Form is subject to the terms of the
6 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
7 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 |
10 | """
11 |
12 | from scompose.project import Project
13 |
14 |
15 | def main(args, parser, extra):
16 | """View or validate a configuration file
17 |
18 | This comes down to reading in the config to the project, at which
19 | case it is validated. We then print it for the user.
20 | """
21 | # Initialize the project
22 | project = Project(
23 | filename=args.file, name=args.project_name, env_file=args.env_file
24 | )
25 |
26 | # Builds any containers into folders
27 | project.view_config()
28 |
--------------------------------------------------------------------------------
/scompose/client/create.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | Copyright (C) 2019-2024 Vanessa Sochat.
4 |
5 | This Source Code Form is subject to the terms of the
6 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
7 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 |
10 | """
11 |
12 | from scompose.project import Project
13 |
14 |
15 | def main(args, parser, extra):
16 | """create one or more instances. If they don't exist, build first.
17 |
18 | This will build and bring up one or more named instances, or if None
19 | are provided, we create all of them.
20 | """
21 | # Initialize the project
22 | project = Project(
23 | filename=args.file, name=args.project_name, env_file=args.env_file
24 | )
25 |
26 | # Create instances, and if none specified, create all
27 | project.create(
28 | args.names,
29 | writable_tmpfs=not args.read_only,
30 | bridge=args.bridge,
31 | no_resolv=args.no_resolv,
32 | )
33 |
--------------------------------------------------------------------------------
/scompose/client/down.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | Copyright (C) 2019-2024 Vanessa Sochat.
4 |
5 | This Source Code Form is subject to the terms of the
6 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
7 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 |
10 | """
11 |
12 | from scompose.project import Project
13 |
14 |
15 | def main(args, parser, extra):
16 | """bring one or more instances down"""
17 | # Initialize the project
18 | project = Project(
19 | filename=args.file, name=args.project_name, env_file=args.env_file
20 | )
21 |
22 | # Create instances, and if none specified, create all
23 | project.down(args.names, args.timeout)
24 |
--------------------------------------------------------------------------------
/scompose/client/exec.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | Copyright (C) 2019-2024 Vanessa Sochat.
4 |
5 | This Source Code Form is subject to the terms of the
6 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
7 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 |
10 | """
11 |
12 | from scompose.project import Project
13 |
14 |
15 | def main(args, parser, extra):
16 | """execute a command to an instance."""
17 | # Initialize the project
18 | project = Project(
19 | filename=args.file, name=args.project_name, env_file=args.env_file
20 | )
21 |
22 | project.execute(args.name[0], extra)
23 |
--------------------------------------------------------------------------------
/scompose/client/logs.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | Copyright (C) 2019-2024 Vanessa Sochat.
4 |
5 | This Source Code Form is subject to the terms of the
6 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
7 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 |
10 | """
11 |
12 | from scompose.project import Project
13 |
14 |
15 | def main(args, parser, extra):
16 | """bring one or more instances down"""
17 | # Initialize the project
18 | project = Project(
19 | filename=args.file, name=args.project_name, env_file=args.env_file
20 | )
21 |
22 | if args.clear:
23 | project.clear_logs(args.names)
24 | else:
25 | project.logs(args.names, args.tail)
26 |
--------------------------------------------------------------------------------
/scompose/client/ps.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | Copyright (C) 2019-2024 Vanessa Sochat.
4 |
5 | This Source Code Form is subject to the terms of the
6 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
7 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 |
10 | """
11 |
12 | from scompose.project import Project
13 |
14 |
15 | def main(args, parser, extra):
16 | """bring one or more instances down"""
17 | # Initialize the project
18 | project = Project(
19 | filename=args.file, name=args.project_name, env_file=args.env_file
20 | )
21 |
22 | # Create instances, and if none specified, create all
23 | project.ps()
24 |
--------------------------------------------------------------------------------
/scompose/client/restart.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | Copyright (C) 2019-2024 Vanessa Sochat.
4 |
5 | This Source Code Form is subject to the terms of the
6 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
7 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 |
10 | """
11 |
12 | from scompose.project import Project
13 |
14 |
15 | def main(args, parser, extra):
16 | """bring up one or more instances. They must exist.
17 |
18 | This will build and bring up one or more named instances, or if None
19 | are provided, we create all of them.
20 | """
21 | # Initialize the project
22 | project = Project(
23 | filename=args.file, name=args.project_name, env_file=args.env_file
24 | )
25 |
26 | # Create instances, and if none specified, create all
27 | project.down(args.names)
28 |
29 | # Create instances, and if none specified, create all
30 | project.up(
31 | args.names,
32 | writable_tmpfs=not args.read_only,
33 | bridge=args.bridge,
34 | no_resolv=args.no_resolv,
35 | )
36 |
--------------------------------------------------------------------------------
/scompose/client/run.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | Copyright (C) 2019-2024 Vanessa Sochat.
4 |
5 | This Source Code Form is subject to the terms of the
6 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
7 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 |
10 | """
11 |
12 | from scompose.project import Project
13 |
14 |
15 | def main(args, parser, extra):
16 | """execute a command to an instance."""
17 | # Initialize the project
18 | project = Project(
19 | filename=args.file, name=args.project_name, env_file=args.env_file
20 | )
21 |
22 | project.run(args.name[0])
23 |
--------------------------------------------------------------------------------
/scompose/client/shell.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | Copyright (C) 2019-2024 Vanessa Sochat.
4 |
5 | This Source Code Form is subject to the terms of the
6 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
7 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 | """
10 |
11 | from scompose.project import Project
12 |
13 |
14 | def main(args, parser, extra):
15 | """bring one or more instances down"""
16 | # Initialize the project
17 | project = Project(
18 | filename=args.file, name=args.project_name, env_file=args.env_file
19 | )
20 |
21 | # Create instances, and if none specified, create all
22 | project.shell(args.name[0])
23 |
--------------------------------------------------------------------------------
/scompose/client/up.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | Copyright (C) 2019-2024 Vanessa Sochat.
4 |
5 | This Source Code Form is subject to the terms of the
6 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
7 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 | """
10 |
11 | from scompose.project import Project
12 |
13 |
14 | def main(args, parser, extra):
15 | """bring up one or more instances. They must exist.
16 |
17 | This will build and bring up one or more named instances, or if None
18 | are provided, we create all of them.
19 | """
20 | # Initialize the project
21 | project = Project(
22 | filename=args.file, name=args.project_name, env_file=args.env_file
23 | )
24 |
25 | # Create instances, and if none specified, create all
26 | project.up(
27 | args.names,
28 | writable_tmpfs=not args.read_only,
29 | bridge=args.bridge,
30 | no_resolv=args.no_resolv,
31 | )
32 |
--------------------------------------------------------------------------------
/scompose/config/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | Copyright (C) 2019-2024 Vanessa Sochat.
4 |
5 | This Source Code Form is subject to the terms of the
6 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
7 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 | """
10 |
11 | import os
12 |
13 | from scompose.logger import bot
14 | from scompose.utils import read_yaml
15 |
16 |
17 | def merge_config(file_list):
18 | """
19 | Given one or more config files, merge into one
20 | """
21 | yaml_files = []
22 | for f in file_list:
23 | try:
24 | # ensure file exists
25 | if not os.path.exists(f):
26 | bot.exit("%s does not exist." % f)
27 |
28 | # read yaml file
29 | yaml_files.append(read_yaml(f, quiet=True))
30 | except Exception: # ParserError
31 | bot.exit("Cannot parse %s, invalid yaml." % f)
32 |
33 | # merge/override yaml properties where applicable
34 | return _deep_merge(yaml_files)
35 |
36 |
37 | def _deep_merge(yaml_files):
38 | """
39 | Merge yaml files into a single dict
40 | """
41 | base_yaml = None
42 | for idx, item in enumerate(yaml_files):
43 | if idx == 0:
44 | base_yaml = item
45 | else:
46 | base_yaml = _merge(base_yaml, item)
47 |
48 | return base_yaml
49 |
50 |
51 | def _merge(a, b):
52 | """
53 | Merge dict b into a
54 | """
55 | for key in b:
56 | if key in a:
57 | # merge dicts recursively
58 | if isinstance(a[key], dict) and isinstance(b[key], dict):
59 | a[key] = _merge(a[key], b[key])
60 | # if types are equal, b takes precedence
61 | elif isinstance(a[key], type(b[key])):
62 | a[key] = b[key]
63 | # if nothing matches then this means a conflict of types which shouldn't exist in the first place
64 | else:
65 | bot.exit("key '%s': type mismatch in different files." % key)
66 | else:
67 | a[key] = b[key]
68 | return a
69 |
--------------------------------------------------------------------------------
/scompose/config/schema.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | Copyright (C) 2021-2024 Vanessa Sochat.
4 |
5 | This Source Code Form is subject to the terms of the
6 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
7 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 | """
10 |
11 | import sys
12 |
13 | from jsonschema.exceptions import ValidationError
14 |
15 | from scompose.utils import read_yaml
16 |
17 | # We don't require jsonschema, so catch import error and alert user
18 | try:
19 | from jsonschema import validate
20 | except ImportError as e:
21 | msg = "pip install jsonschema"
22 | sys.exit("jsonschema is required for checking and validation: %s\n %s" % (e, msg))
23 |
24 |
25 | def validate_config(filepath):
26 | """
27 | Validate a singularity-compose.yaml file.
28 | """
29 | try:
30 | cfg = read_yaml(filepath, quiet=True)
31 | validate(cfg, compose_schema)
32 | return True
33 | except ValidationError:
34 | return False
35 |
36 |
37 | ## Singularity Compose Schema
38 |
39 | schema_url = "https://json-schema.org/draft-07/schema/#"
40 |
41 | # Common patterns of types
42 | string_list = {"type": "array", "items": {"type": "string"}}
43 |
44 | # Instance groups
45 | instance_build = {
46 | "type": "object",
47 | "properties": {
48 | "recipe": {"type": "string"},
49 | "context": {"type": "string"},
50 | "options": string_list,
51 | },
52 | }
53 |
54 | instance_network = {
55 | "type": "object",
56 | "properties": {
57 | "allocate_ip": {"type": "boolean"},
58 | "enable": {"type": "boolean"},
59 | },
60 | }
61 |
62 |
63 | instance_start = {
64 | "type": "object",
65 | "properties": {
66 | "args": {"type": ["string", "array"]},
67 | "background": {"type": "boolean"},
68 | "options": string_list,
69 | },
70 | }
71 |
72 | instance_run = {
73 | "type": "object",
74 | "properties": {
75 | "args": {"type": ["string", "array"]},
76 | "options": string_list,
77 | },
78 | }
79 |
80 | instance_post = {
81 | "type": "object",
82 | "properties": {
83 | "commands": string_list,
84 | },
85 | }
86 |
87 | instance_exec = {
88 | "type": "object",
89 | "properties": {"options": string_list, "command": {"type": "string"}},
90 | "required": [
91 | "command",
92 | ],
93 | }
94 |
95 | instance_deploy = {
96 | "type": "object",
97 | "properties": {
98 | "replicas": {"type": "number", "minimum": 1},
99 | },
100 | }
101 |
102 | # A single instance
103 | instance = {
104 | "type": "object",
105 | "properties": {
106 | "image": {"type": "string"},
107 | "build": instance_build,
108 | "network": instance_network,
109 | "ports": string_list,
110 | "volumes": string_list,
111 | "volumes_from": string_list,
112 | "depends_on": string_list,
113 | "start": instance_start,
114 | "exec": instance_exec,
115 | "run": {"oneOf": [instance_run, {"type": "array"}]},
116 | "post": instance_post,
117 | "deploy": instance_deploy,
118 | },
119 | }
120 |
121 |
122 | # instances define container services
123 | instances = {"type": "object", "patternProperties": {"\\w[\\w-]*": instance}}
124 |
125 | properties = {"version": {"type": "string"}, "instances": instances}
126 |
127 | compose_schema = {
128 | "$schema": schema_url,
129 | "title": "Singularity Compose Schema",
130 | "type": "object",
131 | "required": [
132 | "version",
133 | "instances",
134 | ],
135 | "properties": properties,
136 | "additionalProperties": False,
137 | }
138 |
--------------------------------------------------------------------------------
/scompose/logger/__init__.py:
--------------------------------------------------------------------------------
1 | from .message import bot
2 | from .progress import ProgressBar
3 |
--------------------------------------------------------------------------------
/scompose/logger/progress.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # clint.textui.progress
4 | # ~~~~~~~~~~~~~~~~~~~~~
5 |
6 | # A derivation of clint version, to not introduce a dependency and add custom functionality.
7 | # Credit to base code goes to https://github.com/kennethreitz/clint/blob/master/clint/textui/progress.py
8 |
9 |
10 | from __future__ import absolute_import
11 |
12 | import sys
13 | import time
14 |
15 | STREAM = sys.stderr
16 |
17 | BAR_TEMPLATE = "%s[%s%s] %i/%i MB - %s\r"
18 | BAR_FILLED_CHAR = "-"
19 | BAR_EMPTY_CHAR = " "
20 |
21 | # How long to wait before recalculating the ETA
22 | ETA_INTERVAL = 1
23 | # How many intervals (excluding the current one) to calculate the simple moving
24 | # average
25 | ETA_SMA_WINDOW = 9
26 |
27 |
28 | class ProgressBar:
29 | def __enter__(self):
30 | return self
31 |
32 | def __exit__(self, exc_type, exc_val, exc_tb):
33 | self.done()
34 | return False # we're not suppressing exceptions
35 |
36 | def __init__(
37 | self,
38 | label="",
39 | width=32,
40 | hide=None,
41 | empty_char=BAR_EMPTY_CHAR,
42 | filled_char=BAR_FILLED_CHAR,
43 | expected_size=None,
44 | every=1,
45 | ):
46 | self.label = label
47 | self.width = width
48 | self.hide = hide
49 | # Only show bar in terminals by default (better for piping, logging etc.)
50 | if hide is None:
51 | try:
52 | self.hide = not STREAM.isatty()
53 | except AttributeError: # output does not support isatty()
54 | self.hide = True
55 | self.empty_char = empty_char
56 | self.filled_char = filled_char
57 | self.expected_size = expected_size
58 | self.every = every
59 | self.start = time.time()
60 | self.ittimes = []
61 | self.eta = 0
62 | self.etadelta = time.time()
63 | self.etadisp = self.format_time(self.eta)
64 | self.last_progress = 0
65 | if self.expected_size:
66 | self.show(0)
67 |
68 | def show(self, progress, count=None):
69 | if count is not None:
70 | self.expected_size = count
71 | if self.expected_size is None:
72 | raise Exception("expected_size not initialized")
73 | self.last_progress = progress
74 | if (time.time() - self.etadelta) > ETA_INTERVAL:
75 | self.etadelta = time.time()
76 | self.ittimes = self.ittimes[-ETA_SMA_WINDOW:] + [
77 | -(self.start - time.time()) / (progress + 1)
78 | ]
79 | self.eta = (
80 | sum(self.ittimes)
81 | / float(len(self.ittimes))
82 | * (self.expected_size - progress)
83 | )
84 | self.etadisp = self.format_time(self.eta)
85 | x = int(self.width * progress / self.expected_size)
86 | if not self.hide:
87 | if (progress % self.every) == 0 or ( # True every "every" updates
88 | progress == self.expected_size
89 | ): # And when we're done
90 | STREAM.write(
91 | BAR_TEMPLATE
92 | % (
93 | self.label,
94 | self.filled_char * x,
95 | self.empty_char * (self.width - x),
96 | progress,
97 | self.expected_size,
98 | self.etadisp,
99 | )
100 | )
101 | STREAM.flush()
102 |
103 | def done(self):
104 | self.elapsed = time.time() - self.start
105 | elapsed_disp = self.format_time(self.elapsed)
106 | if not self.hide:
107 | # Print completed bar with elapsed time
108 | STREAM.write(
109 | BAR_TEMPLATE
110 | % (
111 | self.label,
112 | self.filled_char * self.width,
113 | self.empty_char * 0,
114 | self.last_progress,
115 | self.expected_size,
116 | elapsed_disp,
117 | )
118 | )
119 | STREAM.write("\n")
120 | STREAM.flush()
121 |
122 | def format_time(self, seconds):
123 | return time.strftime("%H:%M:%S", time.gmtime(seconds))
124 |
125 |
126 | def bar(
127 | it,
128 | label="",
129 | width=32,
130 | hide=None,
131 | empty_char=BAR_EMPTY_CHAR,
132 | filled_char=BAR_FILLED_CHAR,
133 | expected_size=None,
134 | every=1,
135 | ):
136 | """Progress iterator. Wrap your iterables with it."""
137 |
138 | count = len(it) if expected_size is None else expected_size
139 |
140 | with ProgressBar(
141 | label=label,
142 | width=width,
143 | hide=hide,
144 | empty_char=BAR_EMPTY_CHAR,
145 | filled_char=BAR_FILLED_CHAR,
146 | expected_size=count,
147 | every=every,
148 | ) as pbar:
149 | for i, item in enumerate(it):
150 | yield item
151 | pbar.show(i + 1)
152 |
--------------------------------------------------------------------------------
/scompose/project/__init__.py:
--------------------------------------------------------------------------------
1 | from .project import Project
2 |
--------------------------------------------------------------------------------
/scompose/templates/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | Copyright (C) 2019-2024 Vanessa Sochat.
4 |
5 | This Source Code Form is subject to the terms of the
6 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
7 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 | """
10 |
11 | import os
12 |
13 | from scompose.logger import bot
14 | from scompose.utils import get_installdir
15 |
16 |
17 | def get_template(name):
18 | """get a template by name from this directory. If does not exist,
19 | return None.
20 | """
21 | here = get_installdir()
22 | template = os.path.join(here, "templates", name)
23 | if os.path.exists(template):
24 | return template
25 | bot.warning("%s does not exist." % template)
26 |
--------------------------------------------------------------------------------
/scompose/templates/hosts:
--------------------------------------------------------------------------------
1 | 127.0.0.1 localhost
2 |
3 | # The following lines are desirable for IPv6 capable hosts
4 | ::1 ip6-localhost ip6-loopback
5 | fe00::0 ip6-localnet
6 | ff00::0 ip6-mcastprefix
7 | ff02::1 ip6-allnodes
8 | ff02::2 ip6-allrouters
9 |
--------------------------------------------------------------------------------
/scompose/templates/resolv.conf:
--------------------------------------------------------------------------------
1 | # This is resolv.conf generated by singularity-compose. It is provided
2 | # to provide Google nameservers. If you don't want to have it generated
3 | # and bound by default, use the up --no-resolv argument.
4 |
5 | nameserver 8.8.8.8
6 | nameserver 8.8.4.4
7 |
--------------------------------------------------------------------------------
/scompose/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singularityhub/singularity-compose/ca6fa1834e73e66442a0da01a2246cc86b077b3d/scompose/tests/__init__.py
--------------------------------------------------------------------------------
/scompose/tests/configs/cmd_args/Singularity:
--------------------------------------------------------------------------------
1 | Bootstrap: docker
2 | From: busybox
3 |
4 | %startscript
5 | echo "Following arguments: $@"
6 |
--------------------------------------------------------------------------------
/scompose/tests/configs/cmd_args/singularity-compose.yml:
--------------------------------------------------------------------------------
1 | version: "2.0"
2 | instances:
3 | echo:
4 | build:
5 | context: .
6 | recipe: Singularity
7 | start:
8 | args: "arg0 arg1 arg2"
9 |
--------------------------------------------------------------------------------
/scompose/tests/configs/config_merge/singularity-compose-1.yml:
--------------------------------------------------------------------------------
1 | version: "2.0"
2 | instances:
3 | echo:
4 | build:
5 | context: .
6 | recipe: Singularity
7 | start:
8 | args: "arg0 arg1 arg2"
9 |
--------------------------------------------------------------------------------
/scompose/tests/configs/config_merge/singularity-compose-2.yml:
--------------------------------------------------------------------------------
1 | version: "2.0"
2 | instances:
3 | echo:
4 | start:
5 | options:
6 | - fakeroot
7 | args: "arg0 arg1"
8 |
9 | hello:
10 | image: from_the_other_side.sif
11 | start:
12 | args: "how are you?"
13 |
--------------------------------------------------------------------------------
/scompose/tests/configs/depends_on/Singularity.first:
--------------------------------------------------------------------------------
1 | Bootstrap: docker
2 | From: busybox
3 |
4 | %startscript
5 | printf "Present working directory is $PWD"
6 | printf "This is first"
7 |
--------------------------------------------------------------------------------
/scompose/tests/configs/depends_on/Singularity.second:
--------------------------------------------------------------------------------
1 | Bootstrap: docker
2 | From: busybox
3 |
4 | %startscript
5 | printf "Present working directory is $PWD"
6 | printf "This is second"
7 |
--------------------------------------------------------------------------------
/scompose/tests/configs/depends_on/Singularity.third:
--------------------------------------------------------------------------------
1 | Bootstrap: docker
2 | From: busybox
3 |
4 | %startscript
5 | printf "Present working directory is $PWD"
6 | printf "This is third"
7 |
--------------------------------------------------------------------------------
/scompose/tests/configs/depends_on/singularity-compose.yml:
--------------------------------------------------------------------------------
1 | version: "1.0"
2 | instances:
3 | second:
4 | build:
5 | context: .
6 | recipe: Singularity.second
7 | depends_on: [first]
8 | third:
9 | build:
10 | context: .
11 | recipe: Singularity.third
12 | depends_on: [second]
13 | first:
14 | build:
15 | context: .
16 | recipe: Singularity.first
17 |
--------------------------------------------------------------------------------
/scompose/tests/configs/wrong_depends_on/Singularity.first:
--------------------------------------------------------------------------------
1 | Bootstrap: docker
2 | From: busybox
3 |
4 | %startscript
5 | printf "Present working directory is $PWD"
6 | printf "This is first"
7 |
--------------------------------------------------------------------------------
/scompose/tests/configs/wrong_depends_on/Singularity.second:
--------------------------------------------------------------------------------
1 | Bootstrap: docker
2 | From: busybox
3 |
4 | %startscript
5 | printf "Present working directory is $PWD"
6 | printf "This is second"
7 |
--------------------------------------------------------------------------------
/scompose/tests/configs/wrong_depends_on/Singularity.third:
--------------------------------------------------------------------------------
1 | Bootstrap: docker
2 | From: busybox
3 |
4 | %startscript
5 | printf "Present working directory is $PWD"
6 | printf "This is third"
7 |
--------------------------------------------------------------------------------
/scompose/tests/configs/wrong_depends_on/singularity-compose.yml:
--------------------------------------------------------------------------------
1 | version: "1.0"
2 | instances:
3 | first:
4 | build:
5 | context: .
6 | recipe: Singularity.first
7 | depends_on: [second]
8 | second:
9 | build:
10 | context: .
11 | recipe: Singularity.second
12 | depends_on: [second]
13 | third:
14 | build:
15 | context: .
16 | recipe: Singularity.third
17 |
--------------------------------------------------------------------------------
/scompose/tests/test_client.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | # Copyright (C) 2019-2024 Vanessa Sochat.
4 |
5 | # This Source Code Form is subject to the terms of the
6 | # Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
7 | # with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 | import os
10 | from time import sleep
11 |
12 | import requests
13 |
14 | from scompose.project import Project
15 | from scompose.utils import run_command
16 |
17 |
18 | def test_commands(tmp_path):
19 | tmpdir = os.path.join(tmp_path, "repo")
20 | repo = "https://github.com/singularityhub/singularity-compose-examples"
21 |
22 | # Clone the example
23 | run_command(["git", "clone", repo, tmpdir])
24 |
25 | # Test the simple apache example
26 | workdir = os.path.join(tmpdir, "v1.0", "apache-simple")
27 | os.chdir(workdir)
28 |
29 | # Check for required files
30 | assert "singularity-compose.yml" in os.listdir()
31 |
32 | print("Creating project...")
33 |
34 | # Loading project validates config
35 | project = Project()
36 |
37 | print("Testing build")
38 | assert "httpd.sif" not in os.listdir("httpd")
39 | project.build()
40 | assert "httpd.sif" in os.listdir("httpd")
41 |
42 | print("Testing view config")
43 | project.view_config()
44 |
45 | print("Testing up")
46 | project.up()
47 | assert "etc.hosts" in os.listdir()
48 | assert "resolv.conf" in os.listdir()
49 |
50 | print("Waiting for instance to start")
51 | sleep(10)
52 |
53 | print("Testing logs")
54 | project.logs(["httpd1"], tail=20)
55 |
56 | print("Clearing logs")
57 | project.clear_logs(["httpd1"])
58 | project.logs(["httpd1"], tail=20)
59 |
60 | print("Testing ps")
61 | project.ps()
62 |
63 | print("Testing exec")
64 | project.execute("httpd1", ["echo", "MarsBar"])
65 |
66 | # Ensure running
67 | print(requests.get("http://127.0.0.1").status_code)
68 |
69 | print("Testing down")
70 | project.down()
71 |
72 | print("Testing ip lookup")
73 | lookup = project.get_ip_lookup(["httpd1"])
74 | assert "httpd1" in lookup
75 | assert lookup["httpd1"] == "10.22.0.2"
76 |
--------------------------------------------------------------------------------
/scompose/tests/test_command_args.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | # Copyright (C) 2019-2024 Vanessa Sochat.
4 |
5 | # This Source Code Form is subject to the terms of the
6 | # Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
7 | # with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 | import os
10 | import shutil
11 | from time import sleep
12 |
13 | from scompose.logger import bot
14 | from scompose.project import Project
15 |
16 | here = os.path.dirname(os.path.abspath(__file__))
17 |
18 |
19 | def test_command_args(tmp_path):
20 | bot.clear() ## Clear previously logged messages
21 |
22 | cmd_args = os.path.join(here, "configs", "cmd_args")
23 | for filename in os.listdir(cmd_args):
24 | source = os.path.join(cmd_args, filename)
25 | dest = os.path.join(tmp_path, filename)
26 | print("Copying %s to %s" % (filename, dest))
27 | shutil.copyfile(source, dest)
28 |
29 | # Test the simple apache example
30 | os.chdir(tmp_path)
31 |
32 | # Check for required files
33 | assert "singularity-compose.yml" in os.listdir()
34 |
35 | print("Creating project...")
36 |
37 | # Loading project validates config
38 | project = Project()
39 |
40 | print("Testing build")
41 | project.build()
42 |
43 | assert "echo.sif" in os.listdir(tmp_path)
44 |
45 | print("Testing view config")
46 | project.view_config()
47 |
48 | print("Testing up")
49 | project.up()
50 |
51 | print("Waiting for instances to start")
52 | sleep(10)
53 |
54 | print("Bringing down")
55 | project.down()
56 |
57 | log = bot.get_logs()
58 | assert "arg0 arg1 arg2" in log
59 |
--------------------------------------------------------------------------------
/scompose/tests/test_config.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | # Copyright (C) 2017-2024 Vanessa Sochat.
4 |
5 | # This Source Code Form is subject to the terms of the
6 | # Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
7 | # with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 | import os
10 |
11 | here = os.path.dirname(os.path.abspath(__file__))
12 |
13 |
14 | def test_merge():
15 | print("Testing utils._merge")
16 | from scompose.config import _merge
17 |
18 | # No override
19 | a = {"a": 123}
20 | b = {"b": 456}
21 | assert _merge(a, b) == {"a": 123, "b": 456}
22 |
23 | # Override + merge
24 | a = {"a": 123}
25 | b = {"b": 456, "a": 789}
26 | assert _merge(a, b) == {"a": 789, "b": 456}
27 |
28 | # Override only
29 | a = {"a": 123}
30 | b = {"a": 789}
31 | assert _merge(a, b) == {"a": 789}
32 |
33 | # Dict merge
34 | a = {"a": 123, "b": {"c": "d"}}
35 | b = {"b": {"e": "f"}}
36 | assert _merge(a, b) == {"a": 123, "b": {"c": "d", "e": "f"}}
37 |
38 | # Dict merge + key override
39 | a = {"a": 123, "b": {"c": "d"}}
40 | b = {"b": {"c": "f"}}
41 | assert _merge(a, b) == {"a": 123, "b": {"c": "f"}}
42 |
43 |
44 | def test_deep_merge():
45 | print("Testing utils._deep_merge")
46 | from scompose.config import _deep_merge
47 | from scompose.utils import read_yaml
48 |
49 | config_override = os.path.join(here, "configs", "config_merge")
50 |
51 | # single file
52 | yaml_files = [
53 | read_yaml(
54 | os.path.join(config_override, "singularity-compose-1.yml"), quiet=True
55 | )
56 | ]
57 | ret = _deep_merge(yaml_files)
58 | assert ret["instances"] == {
59 | "echo": {
60 | "build": {"context": ".", "recipe": "Singularity"},
61 | "start": {"args": "arg0 arg1 arg2"},
62 | }
63 | }
64 |
65 | # multiple files
66 | yaml_files = [
67 | read_yaml(
68 | os.path.join(config_override, "singularity-compose-1.yml"), quiet=True
69 | ),
70 | read_yaml(
71 | os.path.join(config_override, "singularity-compose-2.yml"), quiet=True
72 | ),
73 | ]
74 | ret = _deep_merge(yaml_files)
75 | assert ret["instances"] == {
76 | "echo": {
77 | "build": {"context": ".", "recipe": "Singularity"},
78 | "start": {"args": "arg0 arg1", "options": ["fakeroot"]},
79 | },
80 | "hello": {
81 | "image": "from_the_other_side.sif",
82 | "start": {"args": "how are you?"},
83 | },
84 | }
85 |
86 |
87 | def test_merge_config():
88 | print("Testing utils.build_interpolated_config")
89 | from scompose.config import merge_config
90 |
91 | config_override = os.path.join(here, "configs", "config_merge")
92 |
93 | # single file
94 | file_list = [os.path.join(config_override, "singularity-compose-1.yml")]
95 | ret = merge_config(file_list)
96 | assert ret["instances"] == {
97 | "echo": {
98 | "build": {"context": ".", "recipe": "Singularity"},
99 | "start": {"args": "arg0 arg1 arg2"},
100 | }
101 | }
102 |
103 | # multiple files
104 | file_list = [
105 | os.path.join(config_override, "singularity-compose-1.yml"),
106 | os.path.join(config_override, "singularity-compose-2.yml"),
107 | ]
108 | ret = merge_config(file_list)
109 | assert ret["instances"] == {
110 | "echo": {
111 | "build": {"context": ".", "recipe": "Singularity"},
112 | "start": {"args": "arg0 arg1", "options": ["fakeroot"]},
113 | },
114 | "hello": {
115 | "image": "from_the_other_side.sif",
116 | "start": {"args": "how are you?"},
117 | },
118 | }
119 |
--------------------------------------------------------------------------------
/scompose/tests/test_depends_on.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | # Copyright (C) 2019-2024 Vanessa Sochat.
4 |
5 | # This Source Code Form is subject to the terms of the
6 | # Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
7 | # with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 | import os
10 | import shutil
11 | from time import sleep
12 |
13 | from scompose.logger import bot
14 | from scompose.project import Project
15 |
16 | here = os.path.dirname(os.path.abspath(__file__))
17 |
18 |
19 | def test_circular_dependency(tmp_path):
20 | depends_on = os.path.join(here, "configs", "wrong_depends_on")
21 | for filename in os.listdir(depends_on):
22 | source = os.path.join(depends_on, filename)
23 | dest = os.path.join(tmp_path, filename)
24 | print("Copying %s to %s" % (filename, dest))
25 | shutil.copyfile(source, dest)
26 |
27 | # Test the simple apache example
28 | os.chdir(tmp_path)
29 |
30 | # Check for required files
31 | assert "singularity-compose.yml" in os.listdir()
32 |
33 | print("Creating project...")
34 |
35 | # Loading project validates config
36 | project = Project()
37 |
38 | print("Testing build")
39 | project.build()
40 |
41 | for image in ["first.sif", "second.sif", "third.sif"]:
42 | assert image in os.listdir(tmp_path)
43 |
44 | print("Testing view config")
45 | project.view_config()
46 |
47 | try:
48 | print("Testing up")
49 | project.up()
50 | raise Exception("Up should have failed")
51 | except SystemExit:
52 | print("Up failed as expected")
53 | finally:
54 | print("Bringing down")
55 | project.down()
56 |
57 |
58 | def test_no_circular_dependency(tmp_path):
59 | bot.clear() ## Clear previously logged messages
60 |
61 | depends_on = os.path.join(here, "configs", "depends_on")
62 | for filename in os.listdir(depends_on):
63 | source = os.path.join(depends_on, filename)
64 | dest = os.path.join(tmp_path, filename)
65 | print("Copying %s to %s" % (filename, dest))
66 | shutil.copyfile(source, dest)
67 |
68 | # Test the simple apache example
69 | os.chdir(tmp_path)
70 |
71 | # Check for required files
72 | assert "singularity-compose.yml" in os.listdir()
73 |
74 | print("Creating project...")
75 |
76 | # Loading project validates config
77 | project = Project()
78 |
79 | print("Testing build")
80 | project.build()
81 |
82 | for image in ["first.sif", "second.sif", "third.sif"]:
83 | assert image in os.listdir(tmp_path)
84 |
85 | print("Testing view config")
86 | project.view_config()
87 |
88 | # Test depends_on DAG order
89 | keys = list(project.instances.keys())
90 | assert keys == ["first1", "second1", "third1"]
91 |
92 | print("Testing up")
93 | project.up()
94 |
95 | print("Waiting for instances to start")
96 | sleep(10)
97 |
98 | print("Bringing down")
99 | project.down()
100 |
101 | log = bot.get_logs()
102 | assert log.index("Creating first") < log.index("Creating second") and log.index(
103 | "Creating second"
104 | ) < log.index("Creating third")
105 |
--------------------------------------------------------------------------------
/scompose/tests/test_utils.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | # Copyright (C) 2017-2024 Vanessa Sochat.
4 |
5 | # This Source Code Form is subject to the terms of the
6 | # Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
7 | # with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 | import os
10 |
11 | import pytest
12 |
13 | here = os.path.dirname(os.path.abspath(__file__))
14 |
15 |
16 | def test_write_read_files(tmp_path):
17 | """test_write_read_files will test the functions write_file and read_file"""
18 | print("Testing utils.write_file...")
19 | from scompose.utils import write_file
20 |
21 | tmpfile = str(tmp_path / "written_file.txt")
22 | assert not os.path.exists(tmpfile)
23 | write_file(tmpfile, "hello!")
24 | assert os.path.exists(tmpfile)
25 |
26 | print("Testing utils.read_file...")
27 | from scompose.utils import read_file
28 |
29 | content = read_file(tmpfile)[0]
30 | assert content == "hello!"
31 |
32 |
33 | def test_write_bad_json(tmp_path):
34 | from scompose.utils import write_json
35 |
36 | bad_json = {"Wakkawakkawakka'}": [{True}, "2", 3]}
37 | tmpfile = str(tmp_path / "json_file.txt")
38 | assert not os.path.exists(tmpfile)
39 | with pytest.raises(TypeError):
40 | write_json(bad_json, tmpfile)
41 |
42 |
43 | def test_write_json(tmp_path):
44 | import json
45 |
46 | from scompose.utils import read_json, write_json
47 |
48 | good_json = {"Wakkawakkawakka": [True, "2", 3]}
49 | tmpfile = str(tmp_path / "good_json_file.txt")
50 | assert not os.path.exists(tmpfile)
51 | write_json(good_json, tmpfile)
52 | with open(tmpfile, "r") as f:
53 | content = json.loads(f.read())
54 | assert isinstance(content, dict)
55 | assert "Wakkawakkawakka" in content
56 | content = read_json(tmpfile)
57 | assert "Wakkawakkawakka" in content
58 |
59 |
60 | def test_get_installdir():
61 | """get install directory should return the base of where sregistry
62 | is installed
63 | """
64 | print("Testing utils.get_installdir")
65 | from scompose.utils import get_installdir
66 |
67 | whereami = get_installdir()
68 | print(whereami)
69 | assert whereami.endswith("scompose")
70 |
71 |
72 | def test_run_command():
73 | print("Testing utils.run_command")
74 | from scompose.utils import run_command
75 |
76 | result = run_command(["echo", "hello"])
77 | assert result["message"] == "hello\n"
78 | assert result["return_code"] == 0
79 |
80 |
81 | def test_get_userhome():
82 | print("Testing utils.get_userhome")
83 | from scompose.utils import get_userhome
84 |
85 | home = get_userhome()
86 | assert home in os.environ.get("HOME")
87 |
88 |
89 | def test_print_json():
90 | print("Testing utils.print_json")
91 | from scompose.utils import print_json
92 |
93 | result = print_json({1: 1})
94 | assert result == '{\n "1": 1\n}'
95 |
--------------------------------------------------------------------------------
/scompose/utils/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | Copyright (C) 2019-2024 Vanessa Sochat.
4 |
5 | This Source Code Form is subject to the terms of the
6 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
7 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 | """
10 |
11 | import errno
12 | import json
13 | import os
14 | import pwd
15 | import sys
16 | from subprocess import PIPE, STDOUT, Popen
17 |
18 | import yaml
19 |
20 |
21 | def get_installdir():
22 | """get_installdir returns the installation directory of the application"""
23 | return os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
24 |
25 |
26 | def get_userhome():
27 | """get the user home based on the effective uid"""
28 | return pwd.getpwuid(os.getuid())[5]
29 |
30 |
31 | def run_command(cmd, sudo=False):
32 | """run_command uses subprocess to send a command to the terminal.
33 |
34 | Parameters
35 | ==========
36 | cmd: the command to send, should be a list for subprocess
37 | error_message: the error message to give to user if fails,
38 | if none specified, will alert that command failed.
39 |
40 | """
41 | if sudo is True:
42 | cmd = ["sudo"] + cmd
43 |
44 | try:
45 | output = Popen(cmd, stderr=STDOUT, stdout=PIPE)
46 |
47 | except FileNotFoundError:
48 | cmd.pop(0)
49 | output = Popen(cmd, stderr=STDOUT, stdout=PIPE)
50 |
51 | t = output.communicate()[0], output.returncode
52 | output = {"message": t[0], "return_code": t[1]}
53 |
54 | if isinstance(output["message"], bytes):
55 | output["message"] = output["message"].decode("utf-8")
56 |
57 | return output
58 |
59 |
60 | ################################################################################
61 | ## FOLDER OPERATIONS ###########################################################
62 | ################################################################################
63 |
64 |
65 | def mkdir_p(path):
66 | """mkdir_p attempts to get the same functionality as mkdir -p
67 | :param path: the path to create.
68 | """
69 | try:
70 | os.makedirs(path)
71 | except OSError as e:
72 | if e.errno == errno.EEXIST and os.path.isdir(path):
73 | pass
74 | else:
75 | print("Error creating path %s, exiting." % path)
76 | sys.exit(1)
77 |
78 |
79 | ################################################################################
80 | ## FILE OPERATIONS #############################################################
81 | ################################################################################
82 |
83 |
84 | def write_file(filename, content, mode="w"):
85 | """write_file will open a file, "filename" and write content, "content"
86 | and properly close the file
87 | """
88 | with open(filename, mode) as filey:
89 | filey.writelines(content)
90 | return filename
91 |
92 |
93 | def read_file(filename, mode="r", readlines=True):
94 | """write_file will open a file, "filename" and write content, "content"
95 | and properly close the file
96 | """
97 | with open(filename, mode) as filey:
98 | if readlines is True:
99 | content = filey.readlines()
100 | else:
101 | content = filey.read()
102 | return content
103 |
104 |
105 | # Yaml
106 |
107 |
108 | def read_yaml(filename, mode="r", quiet=False):
109 | """read a yaml file, only including sections between dashes"""
110 | stream = read_file(filename, mode, readlines=False)
111 | return _read_yaml(stream, quiet=quiet)
112 |
113 |
114 | def write_yaml(yaml_dict, filename, mode="w"):
115 | """write a dictionary to yaml file
116 |
117 | Parameters
118 | ==========
119 | yaml_dict: the dict to print to yaml
120 | filename: the output file to write to
121 | pretty_print: if True, will use nicer formatting
122 | """
123 | with open(filename, mode) as filey:
124 | filey.writelines(yaml.dump(yaml_dict))
125 | return filename
126 |
127 |
128 | def _read_yaml(section, quiet=False):
129 | """read yaml from a string, either read from file (read_frontmatter) or
130 | from yml file proper (read_yaml)
131 |
132 | Parameters
133 | ==========
134 | section: a string of unparsed yaml content.
135 | """
136 | metadata = {}
137 |
138 | # PyYaml vs pyaml have subtle differences
139 | if hasattr(yaml, "FullLoader"):
140 | docs = yaml.load_all(section, Loader=yaml.FullLoader)
141 | else:
142 | docs = yaml.load_all(section)
143 |
144 | for doc in docs:
145 | if isinstance(doc, dict):
146 | for k, v in doc.items():
147 | if not quiet:
148 | print("%s: %s" % (k, v))
149 | metadata[k] = v
150 | return metadata
151 |
152 |
153 | # Json
154 |
155 |
156 | def write_json(json_obj, filename, mode="w", print_pretty=True):
157 | """write_json will (optionally,pretty print) a json object to file
158 |
159 | Parameters
160 | ==========
161 | json_obj: the dict to print to json
162 | filename: the output file to write to
163 | pretty_print: if True, will use nicer formatting
164 | """
165 | with open(filename, mode) as filey:
166 | if print_pretty:
167 | filey.writelines(print_json(json_obj))
168 | else:
169 | filey.writelines(json.dumps(json_obj))
170 | return filename
171 |
172 |
173 | def print_json(json_obj):
174 | """just dump the json in a "pretty print" format"""
175 | return json.dumps(json_obj, indent=4, separators=(",", ": "))
176 |
177 |
178 | def read_json(filename, mode="r"):
179 | """read_json reads in a json file and returns
180 | the data structure as dict.
181 | """
182 | with open(filename, mode) as filey:
183 | data = json.load(filey)
184 | return data
185 |
--------------------------------------------------------------------------------
/scompose/version.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | Copyright (C) 2019-2024 Vanessa Sochat.
4 |
5 | This Source Code Form is subject to the terms of the
6 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
7 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 | """
10 |
11 | __version__ = "0.1.19"
12 | AUTHOR = "Vanessa Sochat"
13 | AUTHOR_EMAIL = "vsoch@users.noreply.github.com"
14 | NAME = "singularity-compose"
15 | PACKAGE_URL = "http://github.com/singularityhub/singularity-compose"
16 | KEYWORDS = "singularity, compose"
17 | DESCRIPTION = "simple orchestration for singularity containers"
18 | LICENSE = "LICENSE"
19 |
20 | ################################################################################
21 | # Global requirements
22 |
23 |
24 | INSTALL_REQUIRES = (
25 | ("spython", {"min_version": "0.2.11"}),
26 | ("pyaml", {"min_version": "5.1.1"}),
27 | )
28 |
29 | INSTALL_REQUIRES_CHECKS = INSTALL_REQUIRES + (("jsonschema", {"min_version": None}),)
30 |
31 | TESTS_REQUIRES = (("pytest", {"min_version": "4.6.2"}),)
32 |
33 | INSTALL_REQUIRES_ALL = INSTALL_REQUIRES
34 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [flake8]
2 | exclude = benchmarks docs
3 | max-line-length = 100
4 | ignore = E1 E2 E5 W5
5 | per-file-ignores =
6 | scompose/utils/__init__.py:F401
7 | scompose/client/__init__.py:F401
8 | scompose/__init__.py:F401
9 | scompose/config/__init__.py:F401
10 | scompose/logger/__init__.py:F401
11 | scompose/project/__init__.py:F401
12 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from setuptools import find_packages, setup
4 |
5 | ################################################################################
6 | # HELPER FUNCTIONS #############################################################
7 | ################################################################################
8 |
9 |
10 | def get_lookup():
11 | """get version by way of sregistry.version, returns a
12 | lookup dictionary with several global variables without
13 | needing to import singularity
14 | """
15 | lookup = dict()
16 | version_file = os.path.join("scompose", "version.py")
17 | with open(version_file) as filey:
18 | exec(filey.read(), lookup)
19 | return lookup
20 |
21 |
22 | # Read in requirements
23 | def get_reqs(lookup=None, key="INSTALL_REQUIRES"):
24 | """get requirements, mean reading in requirements and versions from
25 | the lookup obtained with get_lookup"""
26 |
27 | if lookup is None:
28 | lookup = get_lookup()
29 |
30 | install_requires = []
31 | for module in lookup[key]:
32 | module_name = module[0]
33 | module_meta = module[1]
34 | if "exact_version" in module_meta:
35 | dependency = "%s==%s" % (module_name, module_meta["exact_version"])
36 | elif "min_version" in module_meta:
37 | if module_meta["min_version"] is None:
38 | dependency = module_name
39 | else:
40 | dependency = "%s>=%s" % (module_name, module_meta["min_version"])
41 | install_requires.append(dependency)
42 | return install_requires
43 |
44 |
45 | # Make sure everything is relative to setup.py
46 | install_path = os.path.dirname(os.path.abspath(__file__))
47 | os.chdir(install_path)
48 |
49 | # Get version information from the lookup
50 | lookup = get_lookup()
51 | VERSION = lookup["__version__"]
52 | NAME = lookup["NAME"]
53 | AUTHOR = lookup["AUTHOR"]
54 | AUTHOR_EMAIL = lookup["AUTHOR_EMAIL"]
55 | PACKAGE_URL = lookup["PACKAGE_URL"]
56 | KEYWORDS = lookup["KEYWORDS"]
57 | DESCRIPTION = lookup["DESCRIPTION"]
58 | LICENSE = lookup["LICENSE"]
59 | with open("README.md") as filey:
60 | LONG_DESCRIPTION = filey.read()
61 |
62 | ################################################################################
63 | # MAIN #########################################################################
64 | ################################################################################
65 |
66 |
67 | if __name__ == "__main__":
68 | INSTALL_REQUIRES = get_reqs(lookup)
69 | INSTALL_REQUIRES_ALL = get_reqs(lookup, "INSTALL_REQUIRES_ALL")
70 | INSTALL_REQUIRES_CHECKS = get_reqs(lookup, "INSTALL_REQUIRES_CHECKS")
71 | TESTS_REQUIRES = get_reqs(lookup, "TESTS_REQUIRES")
72 |
73 | setup(
74 | name=NAME,
75 | version=VERSION,
76 | author=AUTHOR,
77 | author_email=AUTHOR_EMAIL,
78 | maintainer=AUTHOR,
79 | maintainer_email=AUTHOR_EMAIL,
80 | packages=find_packages(),
81 | include_package_data=True,
82 | zip_safe=False,
83 | url=PACKAGE_URL,
84 | license=LICENSE,
85 | description=DESCRIPTION,
86 | long_description=LONG_DESCRIPTION,
87 | long_description_content_type="text/markdown",
88 | keywords=KEYWORDS,
89 | install_requires=INSTALL_REQUIRES,
90 | setup_requires=["pytest-runner"],
91 | tests_require=TESTS_REQUIRES,
92 | extras_require={
93 | "all": [INSTALL_REQUIRES_ALL],
94 | "checks": [INSTALL_REQUIRES_CHECKS],
95 | },
96 | classifiers=[
97 | "Intended Audience :: Science/Research",
98 | "Intended Audience :: Developers",
99 | "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)",
100 | "Programming Language :: C",
101 | "Programming Language :: Python",
102 | "Topic :: Software Development",
103 | "Topic :: Scientific/Engineering",
104 | "Operating System :: Unix",
105 | "Programming Language :: Python :: 2.7",
106 | "Programming Language :: Python :: 3",
107 | ],
108 | entry_points={"console_scripts": ["singularity-compose=scompose.client:start"]},
109 | )
110 |
--------------------------------------------------------------------------------