Repository: mandarons/icloud-drive-docker (python)

Issue:
[FEATURE] Override config path via environment variable ENV_CONFIG_FILE_PATH
**Use case**
In my setup icloud-drive-docker is created by a docker-compose file. I use a large chain of tools to control my environment, so I have a project in my private gitlab, which will setup the container from the docker-compose file via gitlab-runner on my qnap. In this workflow, the config will copied into the container and everything is fine and running.

In this environment, I am running watchtower to update the container if there is a new version. This is working too, but watchtower is not aware that with every container updated the config needs to be placed in the container. 

If the config were in a separate folder from the source I could bind a volume and it would be persistent. 

**Describe the solution you'd like**
Please add an environment variable for DEFAULT_CONFIG_FILE_PATH  like ENV_ICLOUD_PASSWORD_KEY. then I could place the Config file in a save place.


Pull request:
Override config path via environment variable ENV_CONFIG_FILE_PATH
Closes #157 

Patch:
diff --git a/README.md b/README.md
index f88aa18a..ce1fdf9a 100644
--- a/README.md
+++ b/README.md
@@ -36,12 +36,13 @@ services:
       - PUID=<insert the output of `id -u $user`>
       - GUID=<insert the output of `id -g $user`>
     env_file:
-      - .env.icloud #should contain ENV_ICLOUD_PASSWORD=<password>
+      - .env.icloud #should contain ENV_ICLOUD_PASSWORD=<password>, ENV_CONFIG_FILE_PATH=<absolute path in container to config.yaml>
     container_name: icloud
     restart: unless-stopped
     volumes:
       - /etc/timezone:/etc/timezone:ro
       - /etc/localtime:/etc/localtime:ro
+      # To override /app/config.yaml path in container, specify environment variable ENV_CONFIG_FILE_PATH=<absolute path in container to config.yaml>
       - ${PWD}/icloud/config.yaml:/app/config.yaml
       - ${PWD}/icloud/data:/app/icloud
       - ${PWD}/session_data:/app/session_data
diff --git a/src/__init__.py b/src/__init__.py
index af2144c0..a63a6e4b 100644
--- a/src/__init__.py
+++ b/src/__init__.py
@@ -15,6 +15,7 @@ DEFAULT_RETRY_LOGIN_INTERVAL_SEC = 600  # 10 minutes
 DEFAULT_SYNC_INTERVAL_SEC = 1800  # 30 minutes
 DEFAULT_CONFIG_FILE_NAME = "config.yaml"
 ENV_ICLOUD_PASSWORD_KEY = "ENV_ICLOUD_PASSWORD"
+ENV_CONFIG_FILE_PATH_KEY = "ENV_CONFIG_FILE_PATH"
 DEFAULT_LOGGER_LEVEL = "info"
 DEFAULT_LOG_FILE_NAME = "icloud.log"
 DEFAULT_CONFIG_FILE_PATH = os.path.join(
diff --git a/src/sync.py b/src/sync.py
index ad5773d1..b2eb99fb 100644
--- a/src/sync.py
+++ b/src/sync.py
@@ -7,7 +7,9 @@ from time import sleep
 from icloudpy import ICloudPyService, exceptions, utils
 
 from src import (
+    DEFAULT_CONFIG_FILE_PATH,
     DEFAULT_COOKIE_DIRECTORY,
+    ENV_CONFIG_FILE_PATH_KEY,
     ENV_ICLOUD_PASSWORD_KEY,
     LOGGER,
     config_parser,
@@ -52,7 +54,11 @@ def sync():
     photos_sync_interval = 0
     sleep_for = 10
     while True:
-        config = read_config()
+        config = read_config(
+            config_path=os.environ.get(
+                ENV_CONFIG_FILE_PATH_KEY, DEFAULT_CONFIG_FILE_PATH
+            )
+        )
         alive(config=config)
         username = config_parser.get_username(config=config)
         if username:


Test patch:
diff --git a/tests/__init__.py b/tests/__init__.py
index 4652d32b..8bc3cdda 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -10,6 +10,7 @@ from src import usage
 
 DATA_DIR = os.path.join(os.path.dirname(__file__), "data")
 CONFIG_PATH = os.path.join(DATA_DIR, "test_config.yaml")
+ENV_CONFIG_PATH = os.path.join(DATA_DIR, "test_config_env.yaml")
 TEMP_DIR = os.path.join(os.path.dirname(__file__), "temp")
 DRIVE_DIR = os.path.join(TEMP_DIR, "icloud", "drive")
 PHOTOS_DIR = os.path.join(TEMP_DIR, "icloud", "photos")
diff --git a/tests/data/test_config_env.yaml b/tests/data/test_config_env.yaml
new file mode 100644
index 00000000..0142ed22
--- /dev/null
+++ b/tests/data/test_config_env.yaml
@@ -0,0 +1,68 @@
+app:
+  logger:
+    # level - debug, info (default), warning or error
+    level: debug
+    # log filename icloud.log (default)
+    filename: config_loaded_using_env_config_path.log
+  credentials:
+    # iCloud drive username
+    username: user@test.com
+    # Retry failed login (with/without 2FA) every 10 minutes
+    retry_login_interval: 600
+  # Drive destination
+  root: "./icloud"
+  smtp:
+  # If you want to recieve email notifications about expired/missing 2FA credentials then uncomment
+  # email: sender@test.com
+  # Uncomment this if your SMTP username is different than your sender address (for services like AWS SES)
+  # username: ""
+  # default to is same as email above
+  # to: receiver@test.com
+  # password:
+  # host: smtp.test.com
+  # port: 587
+  # If your email provider doesn't handle TLS
+  # no_tls: true
+  # valid values are - global (default - uses .com) or china (uses .com.cn)
+  region: global
+
+drive:
+  destination: "./drive"
+  remove_obsolete: true
+  sync_interval: -1
+  ignore:
+    - "*.psd"
+    - .git/
+  filters:
+    # File filters to be included in syncing iCloud drive content
+    folders:
+      - dir1/dir2/dir3
+      - Keynote
+      - icloudpy
+      - Obsidian
+    file_extensions:
+      # File extensions to be included
+      - pdf
+      - png
+      - jpg
+      - jpeg
+      - md
+      - band
+      - xmcf
+photos:
+  destination: photos
+  remove_obsolete: false
+  sync_interval: -1
+  all_albums: false # Optional, default false. If true preserve album structure. If same photo is in multpile albums creates duplicates on filesystem
+  # folder_format: "%Y/%m" # optional, if set put photos in subfolders according to format. Format cheatsheet - https://strftime.org
+  filters:
+    # if all_albums is false - albums list is used as filter-in, if all_albums is true - albums list is used as filter-out
+    # if albums list is empty and all_albums is false download all photos to "all" folder. if empty and all_albums is true download all folders
+    albums:
+      - "album 2"
+      - album-1
+    file_sizes:
+      # Valid values are [original, medium or thumb]
+      - original
+      - medium
+      - thumb
diff --git a/tests/test_config_parser.py b/tests/test_config_parser.py
index c2b1c996..b0e5bf83 100644
--- a/tests/test_config_parser.py
+++ b/tests/test_config_parser.py
@@ -12,6 +12,7 @@ from src import (
     DEFAULT_RETRY_LOGIN_INTERVAL_SEC,
     DEFAULT_ROOT_DESTINATION,
     DEFAULT_SYNC_INTERVAL_SEC,
+    ENV_CONFIG_FILE_PATH_KEY,
     config_parser,
     read_config,
 )
@@ -20,10 +21,26 @@ from src import (
 class TestConfigParser(unittest.TestCase):
     """Tests for config parser."""
 
+    def tearDown(self):
+        """Clean up."""
+        if ENV_CONFIG_FILE_PATH_KEY in os.environ:
+            os.environ.pop(ENV_CONFIG_FILE_PATH_KEY)
+
     def test_read_config_default_config_path(self):
         """Test for Default config path."""
         self.assertIsNotNone(read_config(config_path=tests.CONFIG_PATH))
 
+    def test_read_config_env_config_path(self):
+        """Test for ENV_CONFIG_FILE_PATH."""
+        os.environ[ENV_CONFIG_FILE_PATH_KEY] = tests.ENV_CONFIG_PATH
+        config = read_config(
+            config_path=os.environ.get(ENV_CONFIG_FILE_PATH_KEY, tests.CONFIG_PATH)
+        )
+        self.assertEqual(
+            config["app"]["logger"]["filename"],
+            "config_loaded_using_env_config_path.log",
+        )
+
     def test_read_config_overridden_config_path(self):
         """Test for Overridden config path."""
         self.assertIsNotNone(read_config(config_path=tests.CONFIG_PATH))