Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions docs/primitives.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,27 @@ __Examples__
environment(variables={'PATH': '/usr/local/bin:$PATH'})
```

# arg
```python
arg(self, **kwargs)
```

The `arg` primitive sets the corresponding environment variables.
These variables could have a default value or not. For the former
case the value should be especified on the command line used to
build the image. This primitive is specific to the Docker container.
For the Singularity and bash container this primitive return only a
empry string.

- __variables__: A dictionary of key / value pairs. The default is an
empty dictionary.

__Examples__

```python
arg(variables={'HTTP_PROXY':'proxy.example.com', 'NO_PROXY':'example.com'})
```

# label
```python
label(self, **kwargs)
Expand Down
3 changes: 2 additions & 1 deletion hpccm/primitives/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from __future__ import absolute_import

__all__ = ['baseimage', 'blob', 'comment', 'copy', 'environment', 'label',
'raw', 'runscript', 'shell', 'user', 'workdir']
'raw', 'runscript', 'shell', 'user', 'workdir', 'arg']

from hpccm.primitives.baseimage import baseimage
from hpccm.primitives.blob import blob
Expand All @@ -28,3 +28,4 @@
from hpccm.primitives.shell import shell
from hpccm.primitives.user import user
from hpccm.primitives.workdir import workdir
from hpccm.primitives.arg import arg
70 changes: 70 additions & 0 deletions hpccm/primitives/arg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# pylint: disable=invalid-name, too-few-public-methods

"""Environment primitive"""

from __future__ import absolute_import
from __future__ import unicode_literals
from __future__ import print_function

import logging # pylint: disable=unused-import

import hpccm.config

from hpccm.common import container_type

class arg(object):
"""The `arg` primitive sets the corresponding environment
variables during the build time of a docker container.
This primitive is docker specific and is ignored for singularity
# Parameters
variables: A dictionary of key / value pairs. The default is an
empty dictionary.
# Examples
```python
arg(variables={'HTTP_PROXY': 'proxy.example.com', 'NO_PROXY':'example.com'})
```
"""

def __init__(self, **kwargs):
"""Initialize primitive"""
self.__variables = kwargs.get('variables', {})

def __str__(self):
"""String representation of the primitive"""
if self.__variables:

if hpccm.config.g_ctype == container_type.SINGULARITY or \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: apptainer/singularity#1676

It is possible to get something like the Dockerfile ARG functionality in Singularity with this approach:
SINGULARITYENV_FOO=bar singularity build foo.sif Singularity.def

where Singularity.def contains

%post
    echo $FOO >> /bar

So I wonder if the "nodefault" case is applicable to Singularity?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is possible to simulate that use case for Singularity. But since for singularity is not as clear the difference of ARG and ENV I do not know if it is better to treat the build time variables using the environment primitive

hpccm.config.g_ctype == container_type.BASH:
return ""
elif hpccm.config.g_ctype == container_type.DOCKER:
string = ""
num_vars = len(self.__variables)
for count, (key, val) in enumerate(sorted(self.__variables.items())):
eol = "" if count == num_vars - 1 else "\n"
if val == "":
string += 'ARG {0}'.format(key) + eol
else:
string += 'ARG {0}={1}'.format(key, val) + eol
return string
else:
raise RuntimeError('Unknown container type')
else:
return ''
119 changes: 119 additions & 0 deletions test/test_arg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# pylint: disable=invalid-name, too-few-public-methods, bad-continuation

"""Test cases for the arg module"""

from __future__ import unicode_literals
from __future__ import print_function

import logging # pylint: disable=unused-import
import unittest

from helpers import bash, docker, invalid_ctype, singularity

from hpccm.primitives.arg import arg

class Test_arg(unittest.TestCase):
def setUp(self):
"""Disable logging output messages"""
logging.disable(logging.ERROR)

@docker
def test_empty(self):
"""No arg specified"""
e = arg()
self.assertEqual(str(e), '')

@invalid_ctype
def test_invalid_ctype(self):
"""Invalid container type specified"""
e = arg(variables={'A': 'B'})
with self.assertRaises(RuntimeError):
str(e)

@docker
def test_single_docker(self):
"""Single arg variable specified"""
e = arg(variables={'A': 'B'})
self.assertEqual(str(e), 'ARG A=B')

@docker
def test_single_docker_nodefault(self):
"""Single arg variable specified (no default value)"""
e = arg(variables={'A': ''})
self.assertEqual(str(e), 'ARG A')

@singularity
def test_single_singularity(self):
"""Single arg variable specified"""
e = arg(variables={'A': 'B'})
self.assertEqual(str(e), '')

@bash
def test_single_bash(self):
"""Single arg variable specified"""
e = arg(variables={'A': 'B'})
self.assertEqual(str(e), '')

@docker
def test_single_export_docker(self):
"""Single arg variable specified"""
e = arg(variables={'A': 'B'})
self.assertEqual(str(e), 'ARG A=B')

@singularity
def test_single_export_singularity(self):
"""Single arg variable specified"""
e = arg(variables={'A': 'B'})
self.assertEqual(str(e),'')

@bash
def test_single_export_bash(self):
"""Single arg variable specified"""
e = arg(variables={'A': 'B'})
self.assertEqual(str(e), '')

@docker
def test_multiple_docker(self):
"""Multiple arg variables specified"""
e = arg(variables={'ONE': 1, 'TWO': 2, 'THREE': 3})
self.assertEqual(str(e),
'''ARG ONE=1
ARG THREE=3
ARG TWO=2''')

@docker
def test_multiple_docker_nodefault(self):
"""Multiple arg variables specified (no default value)"""
e = arg(variables={'ONE': '', 'TWO': '', 'THREE': ''})
self.assertEqual(str(e),
'''ARG ONE
ARG THREE
ARG TWO''')

@singularity
def test_multiple_singularity(self):
"""Multiple arg variables specified"""
e = arg(variables={'ONE': 1, 'TWO': 2, 'THREE': 3},
_export=False)
self.assertEqual(str(e),'')

@bash
def test_multiple_bash(self):
"""Multiple arg variables specified"""
e = arg(variables={'ONE': 1, 'TWO': 2, 'THREE': 3},
_export=False)
self.assertEqual(str(e),'')