Skip to content

Instantly share code, notes, and snippets.

@Gems
Last active October 20, 2023 07:38
Show Gist options
  • Save Gems/a40d7eb45f46c82f990aa7e8845d7e7a to your computer and use it in GitHub Desktop.
Save Gems/a40d7eb45f46c82f990aa7e8845d7e7a to your computer and use it in GitHub Desktop.
A `docker-compose` wrapper for multiple configuration files with relative paths
#!/usr/bin/env bash
TMP_FILE=/tmp/docker-compose.$$.yaml
finish() {
rm ${TMP_FILE} ${TMP_FILE}.tmp 2>/dev/null
}
trap finish EXIT
compose-config() {
mv -f ${TMP_FILE} ${TMP_FILE}.tmp
docker-compose -f ${1} -f ${TMP_FILE}.tmp config >${TMP_FILE}
rm -f ${TMP_FILE}.tmp 2>/dev/null
}
args=()
files=()
while [ -n "$1" ]; do
case "$1" in
-f)
shift; files+=($1)
;;
*)
args+=($1)
;;
esac
shift
done
echo 'version: "3"' >${TMP_FILE}
for f in ${files[@]}; do
compose-config ${f}
done
docker-compose -f ${TMP_FILE} ${args[@]}
exit $?
@bimlas
Copy link

bimlas commented Jul 11, 2022

@Gems, seems to work fine, thanks!

@Gems
Copy link
Author

Gems commented Jul 11, 2022

Thanks for your collaboration, @bimlas 👍🏻

@jneuendorf-i4h
Copy link

jneuendorf-i4h commented Oct 19, 2023

@Gems Thanks for sharing your script. Since I personally prefer using verbose flags when using scripts, I added support for --file:

while [ -n "$1" ]; do
  case "$1" in
    -f | --file)
      shift; files+=($1)
      ;;
    *)
      args+=($1)
      ;;
  esac
  shift
done

Maybe others find that useful, as well. 😉

PS: Also, it seems that one should now use docker compose instead docker-compose.


UPDATE

Here is my final version which also

  • correctly prefixes version: "3"
  • uses a more secure tempfile
  • avoids missing project name
  • correctly override previous config items
#!/usr/bin/env bash

PROJECT_NAME=$(basename `pwd`)

# Create temp file securely
TMP_FILE=`mktemp /tmp/docker-compose.XXXXXX` || exit 1
mv ${TMP_FILE} ${TMP_FILE}.yml
TMP_FILE=${TMP_FILE}.yml

# Clean up
finish() {
  rm ${TMP_FILE} ${TMP_FILE}.tmp 2>/dev/null
}

trap finish EXIT


# Prepend given file to config in order to keep the file's relative context
compose-config() {
  mv -f ${TMP_FILE} ${TMP_FILE}.tmp
  # Add the file twice: 1st for the context, 2nd for config overrides
  docker compose -p ${PROJECT_NAME} -f ${1} -f ${TMP_FILE}.tmp -f ${1} config > ${TMP_FILE}
  rm -f ${TMP_FILE}.tmp 2>/dev/null
}

# Separate -f/--file arguments from the rest
args=()
files=()

while [ -n "$1" ]; do
  case "$1" in
    -f | --file)
      shift; files+=($1)
      ;;
    *)
      args+=($1)
      ;;
  esac
  shift
done

# Generate config
for f in ${files[@]}; do
  compose-config ${f}
done

# Prepend version
mv -f ${TMP_FILE} ${TMP_FILE}.tmp
echo 'version: "3"' > ${TMP_FILE}
cat ${TMP_FILE}.tmp >> ${TMP_FILE}
rm -f ${TMP_FILE}.tmp 2>/dev/null

echo -e "
FINAL CONFIG
------------
"
docker compose -f ${TMP_FILE} config
docker compose -f ${TMP_FILE} ${args[@]}
exit $?

@Gems
Copy link
Author

Gems commented Oct 20, 2023

Thank you for sharing your version @jneuendorf-i4h , I bet many people find it even more useful than the original one 👍🏻

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment