podman-compose icon indicating copy to clipboard operation
podman-compose copied to clipboard

Environment interpolation replacement string

Open zarmhast opened this issue 1 year ago • 4 comments

Describe the bug As described in docker docks https://docs.docker.com/compose/environment-variables/env-file/#interpolation there is an extra form that should be supported in docker-compose.yml file: ${VAR_NAME:+replacement}

To Reproduce

services:
    variables:
        image: busybox
        command: ["/bin/busybox", "sh", "-c", "export | grep EXAMPLE"]
        environment:
            EXAMPLE_REPLACE: ${USER+replaced}

Expected behavior

EXAMPLE_REPLACE=replaced

Actual behavior

EXAMPLE_REPLACE='${USER+replaced}'

Output

$ podman-compose version
using podman version: 4.8.1
podman-compose version  1.0.6
podman --version 
podman version 4.8.1
...

Environment:

  • OS: Linux / WSL / Mac
  • podman version: 4.8.1
  • podman compose version: 1.0.6

Additional context Patch:

Index: podman_compose.py
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/podman_compose.py b/podman_compose.py
--- a/podman_compose.py	(revision bce40c2db30fb0ffb9264b5f51535c26f48fe983)
+++ b/podman_compose.py	(date 1702366787909)
@@ -251,6 +251,8 @@
 # ${VARIABLE-default} default if not set
 # ${VARIABLE:?err} raise error if not set or empty
 # ${VARIABLE?err} raise error if not set
+# ${VARIABLE:+replace} replace if set and not empty
+# ${VARIABLE+replace} replace if set
 # $$ means $
 
 var_re = re.compile(
@@ -262,6 +264,7 @@
             (?P<braced>[_a-zA-Z][_a-zA-Z0-9]*)
             (?:(?P<empty>:)?(?:
                 (?:-(?P<default>[^}]*)) |
+                (?:+(?P<replace>[^}]*)) |
                 (?:\?(?P<err>[^}]*))
             ))?
         })
@@ -287,7 +290,7 @@
             if value == "" and m.group("empty"):
                 value = None
             if value is not None:
-                return str(value)
+                return str(value) if not m.group("replace") else m.group("replace")
             if m.group("err") is not None:
                 raise RuntimeError(m.group("err"))
             return m.group("default") or ""

zarmhast avatar Dec 12 '23 07:12 zarmhast

I would add to this the possibility of nested environment variables substitution for situations like ${VARIABLE:-${VARIABLE:-default}}

Patch:

@@ -248,7 +248,11 @@
 # $VARIABLE
 # ${VARIABLE}
 # ${VARIABLE:-default} default if not set or empty
+# ${VARIABLE:-${VARIABLE:-default | +replace | ?err}}
 # ${VARIABLE-default} default if not set
+# ${VARIABLE-${VARIABLE:-default | +replace | ?err}}
+# ${VARIABLE:+replace} replace if set and not empty
+# ${VARIABLE+replace} replace if set
 # ${VARIABLE:?err} raise error if not set or empty
 # ${VARIABLE?err} raise error if not set
 # $$ means $
@@ -262,6 +266,7 @@
             (?P<braced>[_a-zA-Z][_a-zA-Z0-9]*)
             (?:(?P<empty>:)?(?:
                 (?:-(?P<default>[^}]*)) |
+                (?:\+(?P<replace>[^}]*)) |
                 (?:\?(?P<err>[^}]*))
             ))?
         })
@@ -287,12 +292,14 @@
             if value == "" and m.group("empty"):
                 value = None
             if value is not None:
-                return str(value)
+                return str(value) if not m.group("replace") else m.group("replace")
             if m.group("err") is not None:
                 raise RuntimeError(m.group("err"))
             return m.group("default") or ""
 
         value = var_re.sub(convert, value)
+        # iterate a second time for nested environment variables for default values:
+        value = var_re.sub(convert, value)
     elif hasattr(value, "__iter__"):
         value = [rec_subs(i, subs_dict) for i in value]
     return value

mfloresVicomtech avatar Dec 14 '23 16:12 mfloresVicomtech

I would add to this the possibility of nested environment variables substitution for situations like ${VARIABLE:-${VARIABLE:-default}}

Good point. Unfortunately I don't have the time to come up with a possible solution to support nested variable expansion, less so to create a PR. Would there be any takers?

zarmhast avatar Dec 18 '23 22:12 zarmhast

@mfloresVicomtech, if we are to get into the nitty-gritty of it, then we would also need to update how .env files are being read:

SUBJECT=$USER
MESSAGE=${GREETING:+$GREETING ${SUBJECT}}

docker-compose would read that as SUBJECT=my-user-name and given a GREETING=Hello - MESSAGE="Hello my-user-name".

Whereas podman-compose due to python-dotenv (environs behaves exactly the same) - would fail to expand any variables at all in this scenario! (Compare it to dotenv on npm - doesn't even attempt to expand any variables whatsoever)

zarmhast avatar Dec 18 '23 23:12 zarmhast

please open a PR

Whereas podman-compose due to python-dotenv (environs behaves exactly the same)

dotent is completely different concern docker-compose v1.x (the python version) was using same library

https://github.com/docker/compose/blob/1.28.x/requirements.txt#L16

please don't mix

  • substitution inside compose yaml
  • and substitution inside .env
  • and substitution inside envfile

muayyad-alsadi avatar Dec 19 '23 10:12 muayyad-alsadi