From 7f6c927d4e6d5201c28825bf2e9bc6e72711d940 Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Wed, 25 Oct 2023 14:46:06 +0200
Subject: [PATCH 01/27] ci: add build badge

---
 README.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/README.md b/README.md
index 15dc95a..851a753 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,8 @@
 # Copyright © 2023 Glenn Y. Rolland <glenux@glenux.net>
 -->
 
+[![Build Status](https://cicd.apps.glenux.net/api/badges/glenux/mfm/status.svg)](https://cicd.apps.glenux.net/glenux/mfm)
+
 # Minimalist Fuse Manager (MFM)
 
 MFM is a Crystal-lang CLI designed to streamline the management of various FUSE filesystems, such as sshfs, gocryptfs, httpdirfs, and more. Through its user-friendly interface, users can effortlessly mount and unmount filesystems, get real-time filesystem status, and handle errors proficiently.

From e90b9a2a4c80d2d7eb23dd6d96a8ee80860896c1 Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Wed, 25 Oct 2023 15:24:36 +0200
Subject: [PATCH 02/27] ci: try creating a release automatically

---
 .drone.yml | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/.drone.yml b/.drone.yml
index 0c804e0..56b85f2 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -25,6 +25,7 @@ steps:
     image: curlimages/curl
     environment:
       PACKAGE_UPLOAD_URL: https://code.apps.glenux.net/api/packages/glenux/generic/mfm
+      RELEASES_URL: https://code.apps.glenux.net/api/repos/glenux/releases
       PACKAGE_BASENAME: mfm_linux_amd64
       PACKAGE_UPLOAD_TOKEN:
         from_secret: PACKAGE_UPLOAD_TOKEN
@@ -39,8 +40,22 @@ steps:
       - env |grep DRONE
       - |
         curl -H "Authorization: token $PACKAGE_UPLOAD_TOKEN" \
-             --upload-file /_cache/bin/$PACKAGE_BASENAME \
-           $PACKAGE_UPLOAD_URL/$DRONE_TAG/$PACKAGE_BASENAME
+           --upload-file "/_cache/bin/$PACKAGE_BASENAME" \
+           "$PACKAGE_UPLOAD_URL/$DRONE_TAG/$PACKAGE_BASENAME"
+      - |
+        curl -H "Authorization: token $PACKAGE_UPLOAD_TOKEN" \
+           -X POST \
+           -H "accept: application/json" \
+           -H "content-type: application/json" \
+           -d "{\"tag_name\": \"$DRONE_TAG\", \"target_commitish\": \"$DRONE_COMMIT_SHA\"}" \
+           $RELEASES_URL
+      - |
+        curl -H "Authorization: token $PACKAGE_UPLOAD_TOKEN" \
+           -H  "accept: application/json" \
+           -H  "Content-Type: multipart/form-data" \
+           --upload-file "attachment=@/_cache/bin/$PACKAGE_BASENAME" \
+           "$RELEASES_URL/$DRONE_TAG/assets?name=$PACKAGE_BASENAME"
+
 
 # FIXME: handle multi-arch
 # FIXME: publish only on tags

From ffe68d8658fbeffd82a7aa8e3c81f6920d7d9674 Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Wed, 25 Oct 2023 15:27:55 +0200
Subject: [PATCH 03/27] ci: fix file upload command

---
 .drone.yml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/.drone.yml b/.drone.yml
index 56b85f2..081e834 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -51,9 +51,9 @@ steps:
            $RELEASES_URL
       - |
         curl -H "Authorization: token $PACKAGE_UPLOAD_TOKEN" \
-           -H  "accept: application/json" \
-           -H  "Content-Type: multipart/form-data" \
-           --upload-file "attachment=@/_cache/bin/$PACKAGE_BASENAME" \
+           -H "accept: application/json" \
+           -H "Content-Type: multipart/form-data" \
+           -F "attachment=@/_cache/bin/$PACKAGE_BASENAME" \
            "$RELEASES_URL/$DRONE_TAG/assets?name=$PACKAGE_BASENAME"
 
 

From cd8aef242e806cdad81582d85bbeff183e58dd56 Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Wed, 25 Oct 2023 15:32:11 +0200
Subject: [PATCH 04/27] ci: fix release url

---
 .drone.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.drone.yml b/.drone.yml
index 081e834..f793a8d 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -25,7 +25,7 @@ steps:
     image: curlimages/curl
     environment:
       PACKAGE_UPLOAD_URL: https://code.apps.glenux.net/api/packages/glenux/generic/mfm
-      RELEASES_URL: https://code.apps.glenux.net/api/repos/glenux/releases
+      RELEASES_URL: https://code.apps.glenux.net/api/repos/glenux/mfm/releases
       PACKAGE_BASENAME: mfm_linux_amd64
       PACKAGE_UPLOAD_TOKEN:
         from_secret: PACKAGE_UPLOAD_TOKEN

From 710085311e924130108a45db17bace3053e67bf0 Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Wed, 25 Oct 2023 15:35:41 +0200
Subject: [PATCH 05/27] ci: enable debug

---
 .drone.yml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/.drone.yml b/.drone.yml
index f793a8d..49400ea 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -43,6 +43,7 @@ steps:
            --upload-file "/_cache/bin/$PACKAGE_BASENAME" \
            "$PACKAGE_UPLOAD_URL/$DRONE_TAG/$PACKAGE_BASENAME"
       - |
+        set -x
         curl -H "Authorization: token $PACKAGE_UPLOAD_TOKEN" \
            -X POST \
            -H "accept: application/json" \
@@ -50,6 +51,7 @@ steps:
            -d "{\"tag_name\": \"$DRONE_TAG\", \"target_commitish\": \"$DRONE_COMMIT_SHA\"}" \
            $RELEASES_URL
       - |
+        set -x
         curl -H "Authorization: token $PACKAGE_UPLOAD_TOKEN" \
            -H "accept: application/json" \
            -H "Content-Type: multipart/form-data" \

From c15687115047907530974dec408874e6483053d5 Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Wed, 25 Oct 2023 16:03:22 +0200
Subject: [PATCH 06/27] ci: fix repo token

---
 .drone.yml | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/.drone.yml b/.drone.yml
index 49400ea..744d1f7 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -27,6 +27,8 @@ steps:
       PACKAGE_UPLOAD_URL: https://code.apps.glenux.net/api/packages/glenux/generic/mfm
       RELEASES_URL: https://code.apps.glenux.net/api/repos/glenux/mfm/releases
       PACKAGE_BASENAME: mfm_linux_amd64
+      RELEASE_UPLOAD_TOKEN:
+        from_secret: RELEASE_UPLOAD_TOKEN
       PACKAGE_UPLOAD_TOKEN:
         from_secret: PACKAGE_UPLOAD_TOKEN
     when:
@@ -43,16 +45,16 @@ steps:
            --upload-file "/_cache/bin/$PACKAGE_BASENAME" \
            "$PACKAGE_UPLOAD_URL/$DRONE_TAG/$PACKAGE_BASENAME"
       - |
-        set -x
-        curl -H "Authorization: token $PACKAGE_UPLOAD_TOKEN" \
-           -X POST \
-           -H "accept: application/json" \
-           -H "content-type: application/json" \
-           -d "{\"tag_name\": \"$DRONE_TAG\", \"target_commitish\": \"$DRONE_COMMIT_SHA\"}" \
-           $RELEASES_URL
+        curl -X 'POST' \
+          -H 'Authorization: token $RELEASE_UPLOAD_TOKEN' \
+          -H 'accept: application/json' \
+          -H 'Content-Type: application/json' \
+          -d "{\"body\": \"DRAFT\", \"draft\": true, \"name\": \"DRAFT\", \"prerelease\": false, \"tag_name\": \"$DRONE_TAG\",  \"target_commitish\": \"$DRONE_COMMIT_SHA\"}" \
+          "$RELEASES_URL"
       - |
         set -x
-        curl -H "Authorization: token $PACKAGE_UPLOAD_TOKEN" \
+        curl -X POST \
+           -H "Authorization: token $RELEASE_UPLOAD_TOKEN" \
            -H "accept: application/json" \
            -H "Content-Type: multipart/form-data" \
            -F "attachment=@/_cache/bin/$PACKAGE_BASENAME" \

From 737f93245b006b12a1b12c1de78b1cf11cdc7d0c Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Wed, 25 Oct 2023 16:05:54 +0200
Subject: [PATCH 07/27] ci: fix release name

---
 .drone.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.drone.yml b/.drone.yml
index 744d1f7..533719c 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -49,7 +49,7 @@ steps:
           -H 'Authorization: token $RELEASE_UPLOAD_TOKEN' \
           -H 'accept: application/json' \
           -H 'Content-Type: application/json' \
-          -d "{\"body\": \"DRAFT\", \"draft\": true, \"name\": \"DRAFT\", \"prerelease\": false, \"tag_name\": \"$DRONE_TAG\",  \"target_commitish\": \"$DRONE_COMMIT_SHA\"}" \
+          -d "{\"body\": \"DRAFT\", \"draft\": true, \"name\": \"$DRONE_TAG - DRAFT\", \"prerelease\": false, \"tag_name\": \"$DRONE_TAG\",  \"target_commitish\": \"$DRONE_COMMIT_SHA\"}" \
           "$RELEASES_URL"
       - |
         set -x

From 28762697409b80e2b69640852982037764d45b57 Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Wed, 25 Oct 2023 16:09:06 +0200
Subject: [PATCH 08/27] ci: enable debug

---
 .drone.yml | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/.drone.yml b/.drone.yml
index 533719c..253d2b2 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -24,8 +24,8 @@ steps:
   - name: publish:tag
     image: curlimages/curl
     environment:
-      PACKAGE_UPLOAD_URL: https://code.apps.glenux.net/api/packages/glenux/generic/mfm
-      RELEASES_URL: https://code.apps.glenux.net/api/repos/glenux/mfm/releases
+      PACKAGE_UPLOAD_URL: https://code.apps.glenux.net/api/v1/packages/glenux/generic/mfm
+      RELEASES_URL: https://code.apps.glenux.net/api/v1/repos/glenux/mfm/releases
       PACKAGE_BASENAME: mfm_linux_amd64
       RELEASE_UPLOAD_TOKEN:
         from_secret: RELEASE_UPLOAD_TOKEN
@@ -45,7 +45,8 @@ steps:
            --upload-file "/_cache/bin/$PACKAGE_BASENAME" \
            "$PACKAGE_UPLOAD_URL/$DRONE_TAG/$PACKAGE_BASENAME"
       - |
-        curl -X 'POST' \
+        set -x
+        curl -X POST \
           -H 'Authorization: token $RELEASE_UPLOAD_TOKEN' \
           -H 'accept: application/json' \
           -H 'Content-Type: application/json' \

From 3f6acbbee9ca88ed347f053733deb809f37c6d13 Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Wed, 25 Oct 2023 16:11:52 +0200
Subject: [PATCH 09/27] ci: fix quotes

---
 .drone.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.drone.yml b/.drone.yml
index 253d2b2..6906ead 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -47,7 +47,7 @@ steps:
       - |
         set -x
         curl -X POST \
-          -H 'Authorization: token $RELEASE_UPLOAD_TOKEN' \
+          -H "Authorization: token $RELEASE_UPLOAD_TOKEN" \
           -H 'accept: application/json' \
           -H 'Content-Type: application/json' \
           -d "{\"body\": \"DRAFT\", \"draft\": true, \"name\": \"$DRONE_TAG - DRAFT\", \"prerelease\": false, \"tag_name\": \"$DRONE_TAG\",  \"target_commitish\": \"$DRONE_COMMIT_SHA\"}" \

From 78c040b0994976c9ef03c2aa69365bd69d8df0aa Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Wed, 25 Oct 2023 16:23:16 +0200
Subject: [PATCH 10/27] ci: try fixing file upload

---
 .drone.yml | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/.drone.yml b/.drone.yml
index 6906ead..7e5a675 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -22,7 +22,7 @@ steps:
       - cp -r bin/mfm /_cache/bin/$PACKAGE_BASENAME
 
   - name: publish:tag
-    image: curlimages/curl
+    image: alpine
     environment:
       PACKAGE_UPLOAD_URL: https://code.apps.glenux.net/api/v1/packages/glenux/generic/mfm
       RELEASES_URL: https://code.apps.glenux.net/api/v1/repos/glenux/mfm/releases
@@ -39,6 +39,7 @@ steps:
       - name: cache
         path: /_cache
     commands:
+      - apk add --update --no-cache curl jq
       - env |grep DRONE
       - |
         curl -H "Authorization: token $PACKAGE_UPLOAD_TOKEN" \
@@ -52,6 +53,15 @@ steps:
           -H 'Content-Type: application/json' \
           -d "{\"body\": \"DRAFT\", \"draft\": true, \"name\": \"$DRONE_TAG - DRAFT\", \"prerelease\": false, \"tag_name\": \"$DRONE_TAG\",  \"target_commitish\": \"$DRONE_COMMIT_SHA\"}" \
           "$RELEASES_URL"
+      - |
+        curl -X 'GET' \
+          -H 'accept: application/json' \
+          "$RELEASES_URL/tags/$DRONE_TAG"
+      - |
+        TAG_ID="$(curl -X 'GET' \
+          -H 'accept: application/json' \
+          "$RELEASES_URL/tags/$DRONE_TAG" | jq -r .id)"
+        echo "TAG_ID=$TAG_ID"
       - |
         set -x
         curl -X POST \
@@ -59,7 +69,7 @@ steps:
            -H "accept: application/json" \
            -H "Content-Type: multipart/form-data" \
            -F "attachment=@/_cache/bin/$PACKAGE_BASENAME" \
-           "$RELEASES_URL/$DRONE_TAG/assets?name=$PACKAGE_BASENAME"
+           "$RELEASES_URL/$TAG_ID/assets?name=$PACKAGE_BASENAME"
 
 
 # FIXME: handle multi-arch

From ba45f06b0a70f32faf9d134ac9a0336f3aa3dca3 Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Wed, 25 Oct 2023 16:34:24 +0200
Subject: [PATCH 11/27] doc: fix README about commands

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 851a753..cb91071 100644
--- a/README.md
+++ b/README.md
@@ -49,7 +49,7 @@ Global options:
     -c, --config FILE                Specify configuration file
     -h, --help                       Display this help
 
-Commands:
+Commands (not implemented yet):
     create                           Add a new filesystem
     delete                           Remove an existing filesystem
     edit                             Modify the configuration

From e3e27e9964ab9220f407c6b3b4f9010f0cd11f60 Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Wed, 25 Oct 2023 16:35:24 +0200
Subject: [PATCH 12/27] doc: in README, add link to binary releases

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index cb91071..40370fe 100644
--- a/README.md
+++ b/README.md
@@ -36,7 +36,7 @@ To build from source, you'll also need:
 
 ### 2. Binary Download
 
-Alternatively, download a pre-compiled binary version of MFM.
+Alternatively, download [a pre-compiled binary version](https://code.apps.glenux.net/glenux/mfm/releases) of MFM.
 
 ## Usage
 

From 71dbbb3941e826a12824cc539378edceb3858cf2 Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Wed, 25 Oct 2023 16:38:20 +0200
Subject: [PATCH 13/27] doc: fix wrong license version

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 40370fe..59d276c 100644
--- a/README.md
+++ b/README.md
@@ -102,7 +102,7 @@ Contributing to MFM:
 6. **Submit a Pull Request**: Begin a pull request to the main repository and explain your changes.
 7. **Review**: Await feedback from the maintainers and respond as necessary.
 
-By contributing, you agree to our code of conduct and GPL-2 license terms.
+By contributing, you agree to our code of conduct and license terms.
 
 ## Authors and Contributors
 

From 2d44f1fa779727534333647ee300f7c7efd9115d Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Wed, 25 Oct 2023 22:20:37 +0200
Subject: [PATCH 14/27] ci: enable docker service to prepare for matrix builds

---
 .drone.yml | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/.drone.yml b/.drone.yml
index 7e5a675..ae62da4 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -74,8 +74,17 @@ steps:
 
 # FIXME: handle multi-arch
 # FIXME: publish only on tags
+services:
+  - name: docker
+    image: docker:dind
+    privileged: true
+    volumes:
+      - name: dockersock
+        path: /var/run
 
 volumes:
   - name: cache
     temp: {}
+  - name: dockersock
+    temp: {}
 #

From 5dca1d9f155a441d93ed8367fb86e4f037fe32bb Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Thu, 26 Oct 2023 14:40:39 +0200
Subject: [PATCH 15/27] ci: add crossbuild scripts (drafts)

---
 scripts/ci.crossbuild-alpine.sh | 64 +++++++++++++++++++++++++++++
 scripts/ci.crossbuild-debian.sh | 71 +++++++++++++++++++++++++++++++++
 2 files changed, 135 insertions(+)
 create mode 100755 scripts/ci.crossbuild-alpine.sh
 create mode 100755 scripts/ci.crossbuild-debian.sh

diff --git a/scripts/ci.crossbuild-alpine.sh b/scripts/ci.crossbuild-alpine.sh
new file mode 100755
index 0000000..9a870e6
--- /dev/null
+++ b/scripts/ci.crossbuild-alpine.sh
@@ -0,0 +1,64 @@
+#!/bin/sh -eu
+# vim: set ts=2 sw=2 et:
+
+LOCAL_PROJECT_PATH="${1-$PWD}"
+
+TARGET_ARCH="${2-amd64}"
+
+DOCKER_IMAGE=""
+
+BUILD_COMMAND=" \
+  shards build --static --release \
+  && chown 1000:1000 -R bin \
+  && find bin -type f -maxdepth 1 -exec mv {} {}_${TARGET_ARCH} \; \
+"
+INSTALL_CRYSTAL=" \
+  echo '@edge http://dl-cdn.alpinelinux.org/alpine/edge/community' >>/etc/apk/repositories \
+  && apk add --update --no-cache --force-overwrite \
+    crystal@edge \
+    g++ \
+    gc-dev \
+    libxml2-dev \
+    llvm16-dev \
+    llvm16-static \
+    make \
+    musl-dev \
+    openssl-dev \
+    openssl-libs-static \
+    pcre-dev \
+    shards@edge \
+    yaml-dev \
+    yaml-static \
+    zlib-dev \
+    zlib-static \
+"
+
+# setup arch
+case "$TARGET_ARCH" in
+  amd64) DOCKER_IMAGE="alpine" ;;
+  arm64) DOCKER_IMAGE="multiarch/alpine:aarch64-edge" ;;
+  armel) DOCKER_IMAGE="multiarch/alpine:armv7-edge" ;;
+  # armhf) DOCKER_IMAGE="multiarch/alpine:armhf-edge" ;;
+  # i386)  DOCKER_IMAGE="multiarch/alpine:x86-edge" ;;
+  mips)  DOCKER_IMAGE="multiarch/alpine:mips-edge" ;;
+  mipsel)  DOCKER_IMAGE="multiarch/alpine:mipsel-edge" ;;
+  powerpc)  DOCKER_IMAGE="multiarch/alpine:powerpc-edge" ;;
+  ppc64el)  DOCKER_IMAGE="multiarch/alpine:ppc64el-edge" ;;
+  s390x)  DOCKER_IMAGE="multiarch/alpine:s390x-edge" ;;
+esac
+
+# Compile Crystal project statically for target architecture
+docker pull multiarch/qemu-user-static:register
+docker run \
+  --rm \
+  --privileged \
+  multiarch/qemu-user-static:register \
+  --reset
+docker run \
+  -it \
+  -v "$LOCAL_PROJECT_PATH:/app" \
+  -w /app \
+  --rm \
+  "$DOCKER_IMAGE" \
+  /bin/sh -c "$INSTALL_CRYSTAL && $BUILD_COMMAND"
+
diff --git a/scripts/ci.crossbuild-debian.sh b/scripts/ci.crossbuild-debian.sh
new file mode 100755
index 0000000..379052c
--- /dev/null
+++ b/scripts/ci.crossbuild-debian.sh
@@ -0,0 +1,71 @@
+#!/bin/sh -eu
+# vim: set ts=2 sw=2 et:
+
+LOCAL_PROJECT_PATH="${1-$PWD}"
+
+TARGET_ARCH="${2-amd64}"
+
+DOCKER_IMAGE=""
+
+BUILD_COMMAND=" \
+  shards build --static --release \
+  && chown 1000:1000 -R bin \
+  && find bin -type f -maxdepth 1 -exec mv {} {}_${TARGET_ARCH} \; \
+"
+
+# crystal
+INSTALL_CRYSTAL=" \
+  sed -i -e 's/Types: deb/Types: deb deb-src/' /etc/apt/sources.list.d/debian.sources \
+  && echo 'deb http://deb.debian.org/debian unstable main' > /etc/apt/sources.list.d/sid.list \
+  && echo 'deb-src http://deb.debian.org/debian unstable main' >> /etc/apt/sources.list.d/sid.list \
+  && apt-get update \
+  && apt-get install -y \
+    g++ \
+    libxml2-dev \
+    llvm-dev \
+    make \
+    libssl-dev \
+    libpcre3-dev \
+    libyaml-dev \
+    zlib1g-dev \
+    dpkg-dev \
+    debuild \
+  && apt source crystal \
+  && apt build-dep crystal \
+  && ls -lF \
+  && debuild -b -uc -us \
+"
+
+# setup arch
+case "$TARGET_ARCH" in
+  amd64) DOCKER_IMAGE="debian" ;;
+  arm64) DOCKER_IMAGE="arm64v8/debian" ;;
+  armel) DOCKER_IMAGE="arm32v7/debian" ;;
+  armhf) DOCKER_IMAGE="armhf/debian" ;;
+  i386)  DOCKER_IMAGE="x86/debian" ;;
+  mips)  DOCKER_IMAGE="mips/debian" ;;
+  mipsel)  DOCKER_IMAGE="mipsel/debian" ;;
+  powerpc)  DOCKER_IMAGE="powerpc/debian" ;;
+  ppc64el)  DOCKER_IMAGE="ppc64el/debian" ;;
+  s390x)  DOCKER_IMAGE="s390x/debian" ;;
+esac
+
+# Compile Crystal project statically for target architecture
+docker pull multiarch/qemu-user-static
+
+docker run \
+  --rm \
+  --privileged \
+  multiarch/qemu-user-static \
+  --reset -p yes
+
+set -x
+docker run \
+  -it \
+  -v "$LOCAL_PROJECT_PATH:/app" \
+  -w /app \
+  --rm \
+  --platform linux/arm64 \
+  "$DOCKER_IMAGE" \
+  /bin/sh -c "$INSTALL_CRYSTAL && $BUILD_COMMAND"
+

From 48df4ccc79b45318844d3a7f72592c7d008bded0 Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Thu, 2 Nov 2023 12:41:59 +0100
Subject: [PATCH 16/27] feat: improve crossbuild scripts

---
 scripts/ci.crossbuild-debian.sh       | 11 ++++
 scripts/compiler.crossbuild-debian.sh | 86 +++++++++++++++++++++++++++
 2 files changed, 97 insertions(+)
 create mode 100755 scripts/compiler.crossbuild-debian.sh

diff --git a/scripts/ci.crossbuild-debian.sh b/scripts/ci.crossbuild-debian.sh
index 379052c..cfa6189 100755
--- a/scripts/ci.crossbuild-debian.sh
+++ b/scripts/ci.crossbuild-debian.sh
@@ -59,6 +59,17 @@ docker run \
   multiarch/qemu-user-static \
   --reset -p yes
 
+set -x
+docker run \
+  -it \
+  -v "$LOCAL_PROJECT_PATH:/app" \
+  -w /app \
+  --rm \
+  --platform linux/arm64 \
+  "$DOCKER_IMAGE"
+
+exit 0
+
 set -x
 docker run \
   -it \
diff --git a/scripts/compiler.crossbuild-debian.sh b/scripts/compiler.crossbuild-debian.sh
new file mode 100755
index 0000000..54d8a6e
--- /dev/null
+++ b/scripts/compiler.crossbuild-debian.sh
@@ -0,0 +1,86 @@
+#!/bin/sh -eu
+# vim: set ts=2 sw=2 et:
+
+LOCAL_PROJECT_PATH="${1-$PWD}"
+
+TARGET_ARCH="${2-arm64}"
+
+DOCKER_IMAGE=""
+
+BUILD_COMMAND=" \
+  shards build --static --release \
+  && chown 1000:1000 -R bin \
+  && find bin -type f -maxdepth 1 -exec mv {} {}_${TARGET_ARCH} \; \
+"
+
+# crystal
+INSTALL_CRYSTAL=" \
+  sed -i -e '/^deb/d' /etc/apt/sources.list \
+  && sed -i -e '/jessie.updates/d' /etc/apt/sources.list \
+  && sed -i -e 's/^# deb/deb/' /etc/apt/sources.list \
+  && apt-get update"
+
+cat > /dev/null <<EOF
+"
+  && apt-get install -y \
+    g\+\+ \
+    gcc \
+    curl \
+    autoconf \
+    automake \
+    python2 \
+    libxml2-dev \
+    llvm-dev \
+    make \
+    libssl-dev \
+    libpcre2-dev \
+    libyaml-dev \
+    zlib1g-dev \
+"
+EOF
+
+# setup arch
+case "$TARGET_ARCH" in
+  amd64) DOCKER_IMAGE="debian:8" ;;
+  arm64) DOCKER_IMAGE="arm64v8/debian:8" ;;
+  armel) DOCKER_IMAGE="arm32v7/debian" ;;
+  armhf) DOCKER_IMAGE="armhf/debian" ;;
+  i386)  DOCKER_IMAGE="x86/debian" ;;
+  mips)  DOCKER_IMAGE="mips/debian" ;;
+  mipsel)  DOCKER_IMAGE="mipsel/debian" ;;
+  powerpc)  DOCKER_IMAGE="powerpc/debian" ;;
+  ppc64el)  DOCKER_IMAGE="ppc64el/debian" ;;
+  s390x)  DOCKER_IMAGE="s390x/debian" ;;
+esac
+
+# Compile Crystal project statically for target architecture
+docker pull multiarch/qemu-user-static
+
+docker run \
+  --rm \
+  --privileged \
+  multiarch/qemu-user-static \
+  --reset -p yes
+
+set -x
+docker run \
+  -it \
+  -v "$LOCAL_PROJECT_PATH:/app" \
+  -w /app \
+  --rm \
+  --platform linux/arm64 \
+  "$DOCKER_IMAGE" \
+  /bin/sh -c "$INSTALL_CRYSTAL && bash"
+
+exit 0
+
+set -x
+docker run \
+  -it \
+  -v "$LOCAL_PROJECT_PATH:/app" \
+  -w /app \
+  --rm \
+  --platform linux/arm64 \
+  "$DOCKER_IMAGE" \
+  /bin/sh -c "$INSTALL_CRYSTAL && $BUILD_COMMAND"
+

From 9fc1ec391218ccd2f91c562f07906cde2e3b9072 Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Thu, 2 Nov 2023 12:43:46 +0100
Subject: [PATCH 17/27] feat add support for configurable ssh port

---
 src/filesystems/sshfs.cr | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/filesystems/sshfs.cr b/src/filesystems/sshfs.cr
index 802639b..44ddab9 100644
--- a/src/filesystems/sshfs.cr
+++ b/src/filesystems/sshfs.cr
@@ -12,6 +12,7 @@ module GX
     getter remote_path : String = ""
     getter remote_user : String = ""
     getter remote_host : String = ""
+    getter remote_port : String = "22"
 
     @[YAML::Field(key: "mount_dir", ignore: true)]
     getter mount_dir : String = ""
@@ -34,7 +35,11 @@ module GX
         error = STDERR
         process = Process.new(
           "sshfs", 
-          ["#{remote_user}@#{remote_host}:#{remote_path}", mount_dir], 
+          [
+            "-p", remote_port,
+            "#{remote_user}@#{remote_host}:#{remote_path}", 
+            mount_dir
+          ], 
           input: input, 
           output: output, 
           error: error

From 27508ed5ac3e283ffd0e8a4b348581aeddbf58b3 Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Thu, 2 Nov 2023 12:44:37 +0100
Subject: [PATCH 18/27] feat: add support for version and verbose cli flags

---
 src/cli.cr    | 91 ++++++++++++++++++++++++++++++++-------------------
 src/config.cr | 12 ++++---
 2 files changed, 65 insertions(+), 38 deletions(-)

diff --git a/src/cli.cr b/src/cli.cr
index f60da81..a222201 100644
--- a/src/cli.cr
+++ b/src/cli.cr
@@ -8,6 +8,8 @@ require "./config"
 require "./fzf"
 
 module GX
+  VERSION="v0.1.9"
+
   class Cli
 
     @config : Config
@@ -29,41 +31,55 @@ module GX
         parser.on("-c", "--config FILE", "Set configuration file") do |path|
           @config.path = path
         end
+
+        parser.on("-v", "--verbose", "Set more verbosity") do |flag|
+          @config.verbose = true
+        end
+
+        parser.on("--version", "Show version") do |flag|
+          @config.mode = Config::Mode::ShowVersion
+        end
+
         parser.on("-h", "--help", "Show this help") do |flag|
           STDOUT.puts parser
           exit(0)
         end
 
         parser.separator("\nCommands")
-        parser.on("create", "Create vault") do 
-          @config.mode = Config::Mode::Add
+        parser.on("config", "Manage configuration") do 
+          parser.banner = "Usage: #{PROGRAM_NAME} config [commands] [options]\n\nGlobal options"
+          parser.separator("\nCommands")
 
-          parser.banner = "Usage: #{PROGRAM_NAME} create [options]\n\nGlobal options"
-          parser.separator("\nCommand options")
+          parser.on("create", "Create vault") do 
+            @config.mode = Config::Mode::ConfigAdd
 
-          parser.on("-n", "--name", "Set vault name") do |name|
-            add_args = add_args.merge({ name: name })
+            parser.banner = "Usage: #{PROGRAM_NAME} config create [commands] [options]\n\nGlobal options"
+            parser.separator("\nCommand options")
+
+            parser.on("-n", "--name", "Set vault name") do |name|
+              add_args = add_args.merge({ name: name })
+            end
+            parser.on("-p", "--path", "Set vault encrypted path") do |path|
+              add_args = add_args.merge({ path: path })
+            end
           end
-          parser.on("-p", "--path", "Set vault encrypted path") do |path|
-            add_args = add_args.merge({ path: path })
+
+          parser.on("delete", "Delete vault") do 
+            @config.mode = Config::Mode::ConfigAdd
+
+            parser.banner = "Usage: #{PROGRAM_NAME} delete [options]\n\nGlobal options"
+            parser.separator("\nCommand options")
+
+            parser.on("-n", "--name", "Set vault name") do |name|
+              delete_args = delete_args.merge({ name: name })
+            end
           end
-        end
 
-        parser.on("delete", "Delete vault") do 
-          @config.mode = Config::Mode::Add
-
-          parser.banner = "Usage: #{PROGRAM_NAME} delete [options]\n\nGlobal options"
-          parser.separator("\nCommand options")
-
-          parser.on("-n", "--name", "Set vault name") do |name|
-            delete_args = delete_args.merge({ name: name })
+          parser.on("edit", "Edit configuration") do |flag|
+            @config.mode = Config::Mode::ConfigEdit
           end
         end
 
-        parser.on("edit", "Edit configuration") do |flag|
-          @config.mode = Config::Mode::Edit
-        end
-
       end
       pparser.parse(args)
     end
@@ -71,21 +87,28 @@ module GX
     def run()
       @config.load_from_file
 
+      case @config.mode 
+      when Config::Mode::ShowVersion
+        STDOUT.puts "#{PROGRAM_NAME} #{VERSION}"
+      when Config::Mode::Mount
+        mount
+      end
+    end
+
+    def mount()
       names_display = {} of String => NamedTuple(filesystem: Filesystem, ansi_name: String)
       @config.filesystems.each do |filesystem|
         fs_str = filesystem.type.ljust(12,' ')
-        result_name = 
-          if filesystem.mounted? 
-            "#{fs_str} #{filesystem.name} [open]"
-          else
-            "#{fs_str} #{filesystem.name}"
-          end
-        ansi_name = 
-          if filesystem.mounted? 
-            "#{fs_str.colorize(:dark_gray)} #{filesystem.name} [#{ "open".colorize(:green) }]"
-          else
-            "#{fs_str.colorize(:dark_gray)} #{filesystem.name}"
-          end
+
+        suffix = ""
+        suffix_ansi = ""
+        if filesystem.mounted? 
+          suffix = "[open]"
+          suffix_ansi = "[#{ "open".colorize(:green) }]"
+        end
+
+        result_name = "#{fs_str} #{filesystem.name} #{suffix}".strip
+        ansi_name = "#{fs_str.colorize(:dark_gray)} #{filesystem.name} #{suffix_ansi}".strip
 
         names_display[result_name] = {
           filesystem: filesystem,
@@ -93,7 +116,7 @@ module GX
         }
       end
 
-      result_filesystem_name = Fzf.run(names_display.values.map(&.[:ansi_name]).sort)
+      result_filesystem_name = Fzf.run(names_display.values.map(&.[:ansi_name]).sort).strip
       selected_filesystem = names_display[result_filesystem_name][:filesystem]
       puts ">> #{selected_filesystem.name}".colorize(:yellow)
 
diff --git a/src/config.cr b/src/config.cr
index 18005fc..34df337 100644
--- a/src/config.cr
+++ b/src/config.cr
@@ -8,9 +8,11 @@ require "./filesystems"
 module GX
   class Config
     enum Mode
-      Add
-      Edit
-      Run
+      ConfigAdd
+      ConfigDelete
+      ConfigEdit
+      ShowVersion
+      Mount
     end
 
     record NoArgs
@@ -19,6 +21,7 @@ module GX
 
     getter filesystems : Array(Filesystem)
     getter home_dir : String
+    property verbose : Bool
     property mode : Mode
     property path : String
     property args : AddArgs.class | DelArgs.class | NoArgs.class
@@ -31,7 +34,8 @@ module GX
       end
       @home_dir = ENV["HOME"]
 
-      @mode = Mode::Run
+      @verbose = false
+      @mode = Mode::Mount
       @filesystems = [] of Filesystem
       @path = File.join(@home_dir, ".config", DEFAULT_CONFIG_PATH)
       @args = NoArgs

From afb97e0a895fec0af34494da3514188ba7670d72 Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Thu, 2 Nov 2023 16:55:29 +0100
Subject: [PATCH 19/27] fix: split vagrant provisioning into multiple parts

---
 Vagrantfile                                   |  2 +-
 scripts/vagrant-provision/base.sh             | 32 ++++++++++++++++
 .../build.sh}                                 | 38 -------------------
 scripts/vagrant-provision/recording.sh        | 22 +++++++++++
 4 files changed, 55 insertions(+), 39 deletions(-)
 create mode 100644 scripts/vagrant-provision/base.sh
 rename scripts/{vagrant.provision.sh => vagrant-provision/build.sh} (52%)
 create mode 100644 scripts/vagrant-provision/recording.sh

diff --git a/Vagrantfile b/Vagrantfile
index d5596e1..6ea27b7 100644
--- a/Vagrantfile
+++ b/Vagrantfile
@@ -30,5 +30,5 @@ Vagrant.configure('2') do |config|
     machine.vm.network 'forwarded_port', guest: 80, host: 1080, host_ip: '127.0.0.1'
   end
 
-  config.vm.provision 'shell', path: 'scripts/vagrant.provision.sh'
+  config.vm.provision 'shell', path: 'scripts/vagrant-provision/base.sh'
 end
diff --git a/scripts/vagrant-provision/base.sh b/scripts/vagrant-provision/base.sh
new file mode 100644
index 0000000..4a0d514
--- /dev/null
+++ b/scripts/vagrant-provision/base.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+set -e
+set -u
+
+USER="$(test -d /vagrant && echo "vagrant" || echo "debian")"
+HOSTNAME="$(hostname)"
+
+export DEBIAN_FRONTEND=noninteractive
+
+echo "Installing required system packages"
+apt-get update --allow-releaseinfo-change
+apt-get install -y \
+   apt-transport-https \
+   ca-certificates \
+   git \
+   curl \
+   wget \
+   vim \
+   gnupg2 \
+   software-properties-common
+
+# echo "Installing mfm requirements"
+# apt-get install -y \
+#    fzf \
+#    sshfs \
+#    httpdirfs \
+#    libyaml-0-2 \
+#    libyaml-dev \
+#    libpcre3-dev \
+#    libevent-dev
+
diff --git a/scripts/vagrant.provision.sh b/scripts/vagrant-provision/build.sh
similarity index 52%
rename from scripts/vagrant.provision.sh
rename to scripts/vagrant-provision/build.sh
index a074a0a..6317e22 100644
--- a/scripts/vagrant.provision.sh
+++ b/scripts/vagrant-provision/build.sh
@@ -9,26 +9,6 @@ HOSTNAME="$(hostname)"
 
 export DEBIAN_FRONTEND=noninteractive
 
-echo "Installing required system packages"
-apt-get update --allow-releaseinfo-change
-apt-get install -y \
-   apt-transport-https \
-   ca-certificates \
-   git \
-   curl \
-   wget \
-   vim \
-   gnupg2 \
-   software-properties-common
-
-echo "Installing recording requirements"
-apt-get install -y \
-   tmux \
-   mdp \
-   bat \
-   asciinema \
-   termtosvg
-
 echo "Installing mfm requirements"
 apt-get install -y \
    fzf \
@@ -39,24 +19,6 @@ apt-get install -y \
    libpcre3-dev \
    libevent-dev
 
-#!/bin/sh
-
-set -e
-set -u
-
-USER="$(test -d /vagrant && echo "vagrant" || echo "debian")"
-CLUSTERS_DIR=/home/$USER/clusters
-
-# Installation de kompose
-if [ ! -f /usr/local/bin/kompose ]; then
-	DL="$(mktemp)"
-	curl \
-		-L https://github.com/kubernetes/kompose/releases/download/v1.22.0/kompose-linux-amd64 \
-		-o "$DL"
-	chmod +x "$DL"
-	mv "$DL" /usr/local/bin/kompose
-fi
-
 # Installing asdf
 su - "$USER" -c "git config --global advice.detachedHead false"
 su - "$USER" -c "rm -rf ~/.asdf"
diff --git a/scripts/vagrant-provision/recording.sh b/scripts/vagrant-provision/recording.sh
new file mode 100644
index 0000000..416b802
--- /dev/null
+++ b/scripts/vagrant-provision/recording.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# install crystal
+set -e
+set -u
+
+USER="$(test -d /vagrant && echo "vagrant" || echo "debian")"
+HOSTNAME="$(hostname)"
+
+export DEBIAN_FRONTEND=noninteractive
+
+echo "Installing required system packages"
+apt-get update --allow-releaseinfo-change
+
+echo "Installing recording requirements"
+apt-get install -y \
+   tmux \
+   mdp \
+   bat \
+   asciinema \
+   termtosvg
+

From 47c9dbcd899ad963b657a49dd5aff910e68e3c86 Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Thu, 2 Nov 2023 16:58:39 +0100
Subject: [PATCH 20/27] doc: add required dependencies & debian command

---
 README.md | 24 +++++++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md
index 59d276c..bc58143 100644
--- a/README.md
+++ b/README.md
@@ -19,11 +19,27 @@ Before using MFM, make sure the following tools are installed on your system:
 - **sshfs**: <https://github.com/libfuse/sshfs>
 - **httpdirfs**: <https://github.com/fangfufu/httpdirfs>
 - **fzf**: <https://github.com/junegunn/fzf>
+- libpcre3
+- libevent-2.1
+
+For Debian/Ubuntu you can use the following command:
+
+```shell-session
+$ sudo apt-get update && sudo apt-get install libpcre3 libevent-2.1-7 fzf gocryptfs httpdirfs sshfs
+```
+
+## Building from source
 
 To build from source, you'll also need:
 
 - **crystal-lang**: <https://crystal-lang.org/>
 
+For Debian/Ubuntu you can use the following command:
+
+```shell-session
+$ sudo apt-get update && sudo apt-get install libpcre3-dev libevent-2.1-dev
+```
+
 ## Installation
 
 ### 1. From Source
@@ -36,7 +52,8 @@ To build from source, you'll also need:
 
 ### 2. Binary Download
 
-Alternatively, download [a pre-compiled binary version](https://code.apps.glenux.net/glenux/mfm/releases) of MFM.
+Alternatively, download [a pre-compiled binary
+version](https://code.apps.glenux.net/glenux/mfm/releases) of MFM.
 
 ## Usage
 
@@ -61,7 +78,8 @@ Commands (not implemented yet):
 
 ## Configuration
 
-MFM uses a YAML configuration file, typically found at `~/.config/mfm.yml`, to detail the filesystem names, types, and respective configurations.
+MFM uses a YAML configuration file, typically found at `~/.config/mfm.yml`, to
+detail the filesystem names, types, and respective configurations.
 
 ### YAML File Format
 
@@ -86,7 +104,7 @@ filesystems:
   - type: httpdirfs
     name: "Debian Repository"
     url: "http://ftp.debian.org/debian/"
-  
+
   # Add more filesystems as needed
 ```
 

From f94d0f1f39ac7ae498d76c670e677b0539240728 Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Sat, 18 Nov 2023 19:32:12 +0100
Subject: [PATCH 21/27] fix: add support for global config file

Refs: #14
---
 src/cli.cr    |  3 +++
 src/config.cr | 32 ++++++++++++++++++++++++++++----
 src/main.cr   | 22 ++++++++++++++++++++++
 3 files changed, 53 insertions(+), 4 deletions(-)

diff --git a/src/cli.cr b/src/cli.cr
index a222201..3c0bcf0 100644
--- a/src/cli.cr
+++ b/src/cli.cr
@@ -11,6 +11,7 @@ module GX
   VERSION="v0.1.9"
 
   class Cli
+    Log = ::Log.for("cli")
 
     @config : Config
 
@@ -29,10 +30,12 @@ module GX
         parser.banner = "Usage: #{PROGRAM_NAME} [options]\n\nGlobal options"
 
         parser.on("-c", "--config FILE", "Set configuration file") do |path|
+          Log.info { "Configuration set to #{path}" }
           @config.path = path
         end
 
         parser.on("-v", "--verbose", "Set more verbosity") do |flag|
+          Log.info { "Verbosity enabled" }
           @config.verbose = true
         end
 
diff --git a/src/config.cr b/src/config.cr
index 34df337..f5f6ba0 100644
--- a/src/config.cr
+++ b/src/config.cr
@@ -7,6 +7,8 @@ require "./filesystems"
 
 module GX
   class Config
+    Log = ::Log.for("config")
+
     enum Mode
       ConfigAdd
       ConfigDelete
@@ -26,8 +28,6 @@ module GX
     property path : String
     property args : AddArgs.class | DelArgs.class | NoArgs.class
 
-    DEFAULT_CONFIG_PATH = "mfm.yml"
-
     def initialize()
       if !ENV["HOME"]?
         raise "Home directory not found"
@@ -37,15 +37,39 @@ module GX
       @verbose = false
       @mode = Mode::Mount
       @filesystems = [] of Filesystem
-      @path = File.join(@home_dir, ".config", DEFAULT_CONFIG_PATH)
+      @path = detect_config_file()
+
       @args = NoArgs
     end
 
+    def detect_config_file()
+      possible_files = [
+        File.join(@home_dir, ".config", "mfm", "config.yaml"),
+        File.join(@home_dir, ".config", "mfm", "config.yml"),
+        File.join(@home_dir, ".config", "mfm.yaml"),
+        File.join(@home_dir, ".config", "mfm.yml"),
+        File.join("/etc", "mfm", "config.yaml"),
+        File.join("/etc", "mfm", "config.yml"),
+      ]
+
+      possible_files.each do |file_path|
+        if File.exists?(file_path)
+          Log.info { "Configuration file found: #{file_path}" }
+          return file_path if File.exists?(file_path)
+        else
+          Log.debug { "Configuration file not found: #{file_path}" }
+        end
+      end
+
+      Log.error { "No configuration file found in any of the standard locations" }
+      raise "Configuration file not found"
+    end
+
     def load_from_file
       @filesystems = [] of Filesystem
 
       if !File.exists? @path
-        STDERR.puts "Error: file #{@path} does not exist!".colorize(:red)
+        Log.error { "File #{@path} does not exist!".colorize(:red) }
         exit(1)
       end
       load_filesystems(@path)
diff --git a/src/main.cr b/src/main.cr
index 43192b0..f32183c 100644
--- a/src/main.cr
+++ b/src/main.cr
@@ -6,11 +6,33 @@
 require "yaml"
 require "colorize"
 require "json"
+require "log"
 
 require "./filesystems/gocryptfs"
 require "./config"
 require "./cli"
 
+struct BaseFormat < Log::StaticFormatter
+  def run
+    string @entry.severity.label.downcase
+    string "("
+    source
+    string "): "
+    message
+  end
+end
+
+Log.setup do |config|
+  backend = Log::IOBackend.new(formatter: BaseFormat)
+  config.bind "*", Log::Severity::Info, backend
+
+  if ENV["LOG_LEVEL"]?
+    level = Log::Severity.parse(ENV["LOG_LEVEL"]) || Log::Severity::Info
+    config.bind "*", level, backend
+  end
+end
+
+
 app = GX::Cli.new
 app.parse_command_line(ARGV)
 app.run

From 1c184a55575d5f2e8576e3bbcdca7f738c088881 Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Sat, 18 Nov 2023 23:31:04 +0100
Subject: [PATCH 22/27] fix: delay config file discovery

---
 src/config.cr | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/src/config.cr b/src/config.cr
index f5f6ba0..7a71c9f 100644
--- a/src/config.cr
+++ b/src/config.cr
@@ -25,7 +25,7 @@ module GX
     getter home_dir : String
     property verbose : Bool
     property mode : Mode
-    property path : String
+    property path : String?
     property args : AddArgs.class | DelArgs.class | NoArgs.class
 
     def initialize()
@@ -37,7 +37,7 @@ module GX
       @verbose = false
       @mode = Mode::Mount
       @filesystems = [] of Filesystem
-      @path = detect_config_file()
+      @path = nil
 
       @args = NoArgs
     end
@@ -66,13 +66,18 @@ module GX
     end
 
     def load_from_file
+      path = @path
+      if path.nil?
+        path = detect_config_file()
+      end
+      @path = path
       @filesystems = [] of Filesystem
 
-      if !File.exists? @path
-        Log.error { "File #{@path} does not exist!".colorize(:red) }
+      if !File.exists? path
+        Log.error { "File #{path} does not exist!".colorize(:red) }
         exit(1)
       end
-      load_filesystems(@path)
+      load_filesystems(path)
     end
 
     private def load_filesystems(config_path : String)

From 592f0fbe416d8adaaabe436ed2b4ad481981b8db Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Sat, 18 Nov 2023 19:56:03 +0100
Subject: [PATCH 23/27] fix: add templating support in configuration

Refs: #15
---
 shard.lock    | 3 +++
 shard.yml     | 2 ++
 src/config.cr | 8 +++++++-
 3 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/shard.lock b/shard.lock
index 308912c..8d43fbc 100644
--- a/shard.lock
+++ b/shard.lock
@@ -1,5 +1,8 @@
 version: 2.0
 shards:
+  crinja:
+    git: https://github.com/straight-shoota/crinja.git
+    version: 0.8.1
   shellwords:
     git: https://github.com/sztheory/shellwords-crystal.git
     version: 0.1.0
diff --git a/shard.yml b/shard.yml
index 314293a..746f2c8 100644
--- a/shard.yml
+++ b/shard.yml
@@ -18,6 +18,8 @@ targets:
 #   Short description of gx-vault
 
 dependencies:
+  crinja:
+    github: straight-shoota/crinja
   shellwords:
     github: szTheory/shellwords-crystal
 
diff --git a/src/config.cr b/src/config.cr
index 7a71c9f..913c066 100644
--- a/src/config.cr
+++ b/src/config.cr
@@ -3,6 +3,8 @@
 # SPDX-FileCopyrightText: 2023 Glenn Y. Rolland <glenux@glenux.net>
 # Copyright © 2023 Glenn Y. Rolland <glenux@glenux.net>
 
+require "crinja"
+
 require "./filesystems"
 
 module GX
@@ -81,7 +83,11 @@ module GX
     end
 
     private def load_filesystems(config_path : String)
-      yaml_data = YAML.parse(File.read(config_path))
+      file_data = File.read(config_path)
+      # FIXME: render template on a value basis (instead of global)
+      file_patched = Crinja.render(file_data, {"env" => ENV.to_h}) 
+
+      yaml_data = YAML.parse(file_patched)
       vaults_data = yaml_data["filesystems"].as_a
 
       vaults_data.each do |filesystem_data|

From 9f0902d91d3ea098a9d4be2d109418ee728a0519 Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Sat, 18 Nov 2023 20:03:57 +0100
Subject: [PATCH 24/27] ci: add missing dependencies

---
 .drone.yml | 9 +++++++--
 shard.lock | 1 +
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/.drone.yml b/.drone.yml
index ae62da4..4b41c0d 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -13,11 +13,16 @@ steps:
         path: /_cache
     commands:
       - pwd
-      - apt-get update && 
-          apt-get install -y cmake g++ libevent-dev libpcre3-dev libyaml-dev
+      - |
+        apt-get update && \
+        apt-get install -y \
+          cmake g++ \
+          libevent-dev libpcre3-dev \
+          libyaml-dev liblzma-dev
       - shards install
       - shards build --production --static
       - strip bin/mfm
+      - ./bin/mfm --version
       - mkdir -p /_cache/bin
       - cp -r bin/mfm /_cache/bin/$PACKAGE_BASENAME
 
diff --git a/shard.lock b/shard.lock
index 8d43fbc..c0f0724 100644
--- a/shard.lock
+++ b/shard.lock
@@ -3,6 +3,7 @@ shards:
   crinja:
     git: https://github.com/straight-shoota/crinja.git
     version: 0.8.1
+
   shellwords:
     git: https://github.com/sztheory/shellwords-crystal.git
     version: 0.1.0

From e6a9d0117504083c0ed9ee5a30c90414fc2869d5 Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Sat, 18 Nov 2023 20:19:51 +0100
Subject: [PATCH 25/27] ci: bump crystal version

---
 .drone.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.drone.yml b/.drone.yml
index 4b41c0d..a980769 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -5,7 +5,7 @@ name: default
 
 steps:
   - name: build:binary
-    image: crystallang/crystal:1.7.3
+    image: crystallang/crystal:1.10.1
     environment:
       PACKAGE_BASENAME: mfm_linux_amd64
     volumes:

From 3c4e4271b226d0d08939b6c1cc15db079c92ed0c Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Sat, 18 Nov 2023 23:23:39 +0100
Subject: [PATCH 26/27] ci: switch to alpine for static linking

---
 .drone.yml | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/.drone.yml b/.drone.yml
index a980769..8999d06 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -5,7 +5,7 @@ name: default
 
 steps:
   - name: build:binary
-    image: crystallang/crystal:1.10.1
+    image: crystallang/crystal:1.10.1-alpine
     environment:
       PACKAGE_BASENAME: mfm_linux_amd64
     volumes:
@@ -13,12 +13,12 @@ steps:
         path: /_cache
     commands:
       - pwd
-      - |
-        apt-get update && \
-        apt-get install -y \
-          cmake g++ \
-          libevent-dev libpcre3-dev \
-          libyaml-dev liblzma-dev
+        # - |
+        #   apt-get update && \
+        #   apt-get install -y \
+        #     cmake g++ \
+        #     libevent-dev libpcre3-dev \
+        #     libyaml-dev liblzma-dev
       - shards install
       - shards build --production --static
       - strip bin/mfm

From 5e8c46dfcf48511d6836c28cf5c053ce484b2e13 Mon Sep 17 00:00:00 2001
From: Glenn <glenux@glenux.net>
Date: Sat, 18 Nov 2023 23:35:54 +0100
Subject: [PATCH 27/27] fix: delay config loading

---
 src/cli.cr | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/cli.cr b/src/cli.cr
index 3c0bcf0..48b3393 100644
--- a/src/cli.cr
+++ b/src/cli.cr
@@ -88,12 +88,11 @@ module GX
     end
 
     def run()
-      @config.load_from_file
-
       case @config.mode 
       when Config::Mode::ShowVersion
         STDOUT.puts "#{PROGRAM_NAME} #{VERSION}"
       when Config::Mode::Mount
+        @config.load_from_file
         mount
       end
     end