Skip to content

Instantly share code, notes, and snippets.

@sebpiq
Last active May 27, 2024 14:42
Show Gist options
  • Save sebpiq/02589f499c9920e70e924580a3fa9b9e to your computer and use it in GitHub Desktop.
Save sebpiq/02589f499c9920e70e924580a3fa9b9e to your computer and use it in GitHub Desktop.
envstore.py workaround for reusing the result of previous commands in a Dockerfile.
# In the following example usage of envstore.py, we want to get dynamically the home directory
# of a newly created user.
# We run the command to get that directory path once, and store the result using `envstore.py`
# with key `USER_HOME`.
FROM ubuntu:bionic
# Python 3.7 is needed for envstore.py
RUN apt-get update && apt-get install -qy software-properties-common
RUN add-apt-repository -y ppa:deadsnakes/ppa
RUN apt-get update && apt-get install -qy python3.7
COPY envstore.py /usr/local/bin
# Running the tests
RUN envstore.py test
# Create a new user
ENV USER john
RUN adduser --disabled-password --gecos "" $USER
# Stores the new user home directory to variable USER_HOME
RUN envstore.py set USER_HOME $(getent passwd $USER | cut -f6 -d":")
# New User always gets greeted when starting bash session
RUN echo "echo 'greetings!!!'" >> $(envstore.py get USER_HOME)/.bashrc
#!/usr/bin/env python3.7
import os
import sys
HOME = os.environ.get('HOME', '/root')
ENV_JSON_PATH = os.path.join(HOME, 'envstore.env')
def load_env_dict():
if not os.path.exists(ENV_JSON_PATH):
return None
with open(ENV_JSON_PATH, 'r') as fd:
env_str = fd.read()
env_str = env_str.strip()
env_dict = {}
for pair in env_str.split('\n'):
if not pair:
continue
key, value = pair.split('=')
env_dict[key] = value
return env_dict
def write_env_dict(env_dict):
env_str = '\n'.join([ f'{k}={v}\n' for k, v in env_dict.items() ])
with open(ENV_JSON_PATH, 'w') as fd:
fd.write(env_str)
def get_var(name):
env_dict = load_env_dict() or {}
return env_dict[name]
def set_var(name, value):
env_dict = load_env_dict() or {}
env_dict[name] = value
write_env_dict(env_dict)
def print_usage(exit_code=None):
print(
f'Minimalist environment variable store for usage with docker.\nUsage : \n'
f'\t{sys.argv[0]} get <key>\n'
f'\t{sys.argv[0]} set <key> <value>'
)
if exit_code is not None:
sys.exit(exit_code)
def main(args):
if len(args) < 1:
print_usage(1)
command = args.pop(0)
if command == 'get':
if len(args) != 1:
print_usage(1)
key = args.pop(0)
try:
print(get_var(key))
except KeyError:
sys.stderr.write(f'Unknown key "{key}"\n')
elif command == 'set':
if len(args) != 2:
print_usage(1)
key = args.pop(0)
value = args.pop(0)
set_var(key, value)
elif command == 'test':
import unittest
global ENV_JSON_PATH
ENV_JSON_PATH = '/tmp/envstore.json'
class BaseTestCase(unittest.TestCase):
def setUp(self):
with open(ENV_JSON_PATH, 'w') as fd:
fd.write('bla=haha')
class TestGetSetUnit(BaseTestCase):
def test_get_var_existing(self):
self.assertEqual(get_var('bla'), 'haha')
def test_get_var_unknown(self):
with self.assertRaises(KeyError):
get_var('blo')
def test_get_var_file_unexisting(self):
os.remove(ENV_JSON_PATH)
with self.assertRaises(KeyError):
get_var('blo')
def test_set_var_existing(self):
set_var('bla', 'hoho')
self.assertEqual(get_var('bla'), 'hoho')
def test_set_var_new(self):
set_var('blo', 'hihi')
self.assertEqual(get_var('bla'), 'haha')
self.assertEqual(get_var('blo'), 'hihi')
class TestCommands(BaseTestCase):
def test_get_command(self):
main(['get', 'bla'])
def test_set_command(self):
main(['set', 'bla', 'hoho'])
self.assertEqual(get_var('bla'), 'hoho')
unittest.TextTestRunner(verbosity=2).run(unittest.TestSuite([
unittest.TestLoader().loadTestsFromTestCase(TestGetSetUnit),
unittest.TestLoader().loadTestsFromTestCase(TestCommands)
]))
else:
print(f'ERROR: unrecognized command {command}')
print_usage(1)
if __name__ == '__main__':
args = sys.argv[1:]
main(args)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment