From 46112a9d43eeada70f80475d3077b9a3f47ac43f Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Sat, 3 Aug 2024 17:29:43 -0700 Subject: [PATCH 1/4] container: add preliminary bash autocompletion --- container/src/finance/completion.bash | 100 ++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 container/src/finance/completion.bash diff --git a/container/src/finance/completion.bash b/container/src/finance/completion.bash new file mode 100644 index 0000000..510d7b2 --- /dev/null +++ b/container/src/finance/completion.bash @@ -0,0 +1,100 @@ +#!/usr/bin/env bash + +# docker-finance | modern accounting for the power-user +# +# Copyright (C) 2024 Aaron Fiore (Founder, Evergreen Crypto LLC) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +[ -z "$DOCKER_FINANCE_CONTAINER_FLOW" ] && exit 1 + +function docker-finance::completion() +{ + local -r _cur="${COMP_WORDS[COMP_CWORD]}" + local -r _prev="${COMP_WORDS[COMP_CWORD - 1]}" + + local _profiles + mapfile -t _profiles < <(pushd "${DOCKER_FINANCE_CONTAINER_FLOW}"/profiles &>/dev/null && ls -d */*) + declare -r _profiles + + local -r _commands=("all" "edit" "fetch" "import" "ledger" "ledger-ui" "ledger-web" "meta" "reports" "root" "taxes") + + local _reply + + case $COMP_CWORD in + 1) + mapfile -t _reply < <(compgen -W "${_profiles[*]}" -- "$_cur") + declare -r _reply + COMPREPLY=("${_reply[@]}") + ;; + 2) + mapfile -t _reply < <(compgen -W "${_commands[*]}" -- "$_cur") + declare -r _reply + COMPREPLY=("${_reply[@]}") + ;; + 3) + # NOTE: same as in impl + [ -z "$global_arg_delim_2" ] && global_arg_delim_2="=" + + # Disable space after completion + compopt -o nospace + + case "$_prev" in + all) + mapfile -t _reply < <(compgen -W "help year${global_arg_delim_2}" -- "$_cur") + ;; + edit) + mapfile -t _reply < <(compgen -W "help type${global_arg_delim_2} account${global_arg_delim_2}" -- "$_cur") + ;; + fetch) + mapfile -t _reply < <(compgen -W "help all${global_arg_delim_2} price${global_arg_delim_2} api${global_arg_delim_2} account${global_arg_delim_2} year${global_arg_delim_2} chain${global_arg_delim_2} blockchain${global_arg_delim_2}" -- "$_cur") + ;; + import) + mapfile -t _reply < <(compgen -W "help year${global_arg_delim_2}" -- "$_cur") + ;; + ledger | hledger) + mapfile -t _reply < <(compgen -W "-h" -- "$_cur") + ;; + ledger-ui | hledger-ui) + mapfile -t _reply < <(compgen -W "-h" -- "$_cur") + ;; + ledger-web | hledger-web) + mapfile -t _reply < <(compgen -W "-h" -- "$_cur") + ;; + meta) + # NOTE: args are dependent upon metadata contents + mapfile -t _reply < <(compgen -W "help" -- "$_cur") + ;; + reports) + mapfile -t _reply < <(compgen -W "help all${global_arg_delim_2} type${global_arg_delim_2} interval${global_arg_delim_2} year${global_arg_delim_2}" -- "$_cur") + ;; + root) + # TODO: currently no-op + ;; + taxes) + mapfile -t _reply < <(compgen -W "help all${global_arg_delim_2} tag${global_arg_delim_2} account${global_arg_delim_2} year${global_arg_delim_2} write${global_arg_delim_2}" -- "$_cur") + ;; + esac + declare -r _reply + COMPREPLY=("${_reply[@]}") + ;; + *) + COMPREPLY=() + ;; + esac +} + +complete -F docker-finance::completion finance +complete -F docker-finance::completion finance.bash +complete -F docker-finance::completion docker-finance From 7f86b6a2503c8d26d09a3236acfb6ee816e0717d Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Sat, 3 Aug 2024 19:07:35 -0700 Subject: [PATCH 2/4] client: add preliminary bash completion --- client/src/docker/completion.bash | 99 +++++++++++++++++++++++++++++++ client/src/docker/docker.bash | 10 ++-- 2 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 client/src/docker/completion.bash diff --git a/client/src/docker/completion.bash b/client/src/docker/completion.bash new file mode 100644 index 0000000..1cbb6d7 --- /dev/null +++ b/client/src/docker/completion.bash @@ -0,0 +1,99 @@ +#!/usr/bin/env bash + +# docker-finance | modern accounting for the power-user +# +# Copyright (C) 2024 Aaron Fiore (Founder, Evergreen Crypto LLC) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# If not yet installed, gracefully exit +if ! hash docker &>/dev/null; then + exit 0 +fi + +function docker-finance::completion() +{ + local _cur="${COMP_WORDS[COMP_CWORD]}" + local _prev="${COMP_WORDS[COMP_CWORD - 1]}" + + local _images + mapfile -t _images < <(docker image ls | grep ^docker-finance | cut -d'/' -f2- | cut -d' ' -f1-4 | sed -e 's/ /:/') + declare -r _images + + local -r _commands=("gen" "edit" "build" "backup" "rm" "up" "down" "start" "stop" "run" "shell" "version" "license" "linter" "doxygen") + + local _reply + + case $COMP_CWORD in + 1) + mapfile -t _reply < <(compgen -W "${_images[*]}" -- "$_cur") + declare -r _reply + # TODO: HACK for colon tag. Consider using bash-completion package. + for _r in "${_reply[@]}"; do + COMPREPLY+=("'${_r}'") + done + ;; + 2) + mapfile -t _reply < <(compgen -W "${_commands[*]}" -- "$_cur") + declare -r _reply + COMPREPLY=("${_reply[@]}") + ;; + # TODO: multiple options (in 3) should have multiple completions + 3) + # NOTE: same as in client impl + [ -z "$global_arg_delim_2" ] && global_arg_delim_2="=" + + # Disable space after completion + compopt -o nospace + + case "$_prev" in + gen) + # TODO: _currently no-op + ;; + edit) + mapfile -t _reply < <(compgen -W "help type${global_arg_delim_2}" -- "$_cur") + ;; + build) + mapfile -t _reply < <(compgen -W "help type${global_arg_delim_2}" -- "$_cur") + ;; + backup | rm | up | down | start | stop) + # TODO: _currently no-op + ;; + shell) + mapfile -t _reply < <(compgen -W "help user${global_arg_delim_2}" -- "$_cur") + ;; + version) + mapfile -t _reply < <(compgen -W "help type${global_arg_delim_2}" -- "$_cur") + ;; + license) + mapfile -t _reply < <(compgen -W "help file${global_arg_delim_2}" -- "$_cur") + ;; + linter) + mapfile -t _reply < <(compgen -W "help type${global_arg_delim_2} file${global_arg_delim_2}" -- "$_cur") + ;; + doxygen) + mapfile -t _reply < <(compgen -W "help gen${global_arg_delim_2} rm${global_arg_delim_2}" -- "$_cur") + ;; + esac + declare -r _reply + COMPREPLY=("${_reply[@]}") + ;; + *) + COMPREPLY=() + ;; + esac +} + +complete -F docker-finance::completion docker.bash +complete -F docker-finance::completion docker-finance diff --git a/client/src/docker/docker.bash b/client/src/docker/docker.bash index fa69673..e917df3 100755 --- a/client/src/docker/docker.bash +++ b/client/src/docker/docker.bash @@ -95,8 +95,9 @@ function main() \e[37;2m# Finance platform\e[0m \e[37;2m#\e[0m - \e[37;2m# Setup an alias for latest \e[0m - $ alias docker-finance=\"$0 archlinux${global_arg_delim_1}${USER}:latest\" + \e[37;2m# For the sake of simplicity, recreate the docker-finance alias using \e[0m + $ unalias docker-finance 2>/dev/null \\ + ; alias docker-finance=\"$0 archlinux${global_arg_delim_1}${USER}:default\" \e[37;2m# Generate environment and build default image\e[0m $ docker-finance gen && docker-finance build type${global_arg_delim_2}default @@ -127,8 +128,9 @@ function main() \e[37;2m# Dev-tools platform\e[0m \e[37;2m#\e[0m - \e[37;2m# Setup an alias for dev-tools\e[0m - $ alias dev-tools=\"$0 dev-tools${global_arg_delim_1}${USER}:latest\" + \e[37;2m# For the sake of simplicity, recreate the dev-tools alias using \e[0m + $ unalias dev-tools 2>/dev/null \\ + ; alias dev-tools=\"$0 dev-tools${global_arg_delim_1}${USER}:default\" \e[37;2m# Generate environment and build default image\e[0m $ dev-tools gen && dev-tools build type${global_arg_delim_2}default From 646ca3af85c61a9bd0dde4f76dbbab5e452f1957 Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Sat, 3 Aug 2024 19:32:17 -0700 Subject: [PATCH 3/4] Dockerfiles: source container bash completion --- client/Dockerfiles/finance/Dockerfile.archlinux.in | 3 ++- client/Dockerfiles/finance/Dockerfile.ubuntu.in | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/client/Dockerfiles/finance/Dockerfile.archlinux.in b/client/Dockerfiles/finance/Dockerfile.archlinux.in index c6a75e7..1e93fe7 100644 --- a/client/Dockerfiles/finance/Dockerfile.archlinux.in +++ b/client/Dockerfiles/finance/Dockerfile.archlinux.in @@ -78,11 +78,12 @@ RUN composer require ozdemirburak/json-csv RUN composer require ccxt/ccxt # -# Superscript +# Shell environment # USER @DOCKER_FINANCE_USER@ RUN echo "source \"\${DOCKER_FINANCE_CONTAINER_CONF}/shell/superscript.bash\"" | tee -a ~/.bashrc +RUN echo "source \"\${DOCKER_FINANCE_CONTAINER_REPO}/src/finance/completion.bash\"" | tee -a ~/.bashrc # # Entrypoint diff --git a/client/Dockerfiles/finance/Dockerfile.ubuntu.in b/client/Dockerfiles/finance/Dockerfile.ubuntu.in index 1b2011a..15d619c 100644 --- a/client/Dockerfiles/finance/Dockerfile.ubuntu.in +++ b/client/Dockerfiles/finance/Dockerfile.ubuntu.in @@ -82,11 +82,12 @@ RUN composer require ozdemirburak/json-csv RUN composer require ccxt/ccxt # -# Superscript +# Shell environment # USER @DOCKER_FINANCE_USER@ RUN echo "source \"\${DOCKER_FINANCE_CONTAINER_CONF}/shell/superscript.bash\"" | tee -a ~/.bash_aliases +RUN echo "source \"\${DOCKER_FINANCE_CONTAINER_REPO}/src/finance/completion.bash\"" | tee -a ~/.bash_aliases # # Entrypoint From ef5eda8ce809798edf0dccef079ed9b5cda461ec Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Sat, 3 Aug 2024 20:05:02 -0700 Subject: [PATCH 4/4] README: add bash completion to install --- README.md | 93 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 71 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index b024852..2ae3f00 100644 --- a/README.md +++ b/README.md @@ -243,6 +243,8 @@ Supported blockchains (independent of wallet type): ### Installation +[//]: # (TODO: move step 3 to installation script, add `dfi` aliases, update README) + `docker-finance` is not your typical Docker image in which you simply pull and containerize, but rather it's an *image-based* accounting system that operates transparently between your client (host) and container; keeping your finances containerized, with all the benefits of containerization. `docker-finance` *should* work out-of-the-box on any modern Linux system. For example, if your client (host) is Ubuntu, the default installation of `coreutils`, `shells` and `utils` that came with your system will satisfy requirements. However, you'll still need to manually install Docker (see below). @@ -262,12 +264,36 @@ Supported blockchains (independent of wallet type): - Safely track your workflow related data (journals, metadata, etc.) 2. Consider using a terminal multiplexer like [tmux](https://github.com/tmux/tmux/wiki) or [screen](https://www.gnu.org/software/screen/) for optimal workflow efficiency -3. **Copy/paste the following into your `bash` shell** (one-time repository clone and client preparation): +3. **Copy/paste the following into your `bash` shell** (client preparation): ```bash bashrc=~/.bashrc aliases=~/.bash_aliases + function docker-finance::install() + { + # Environment expectations + _alias="alias docker-finance=" + _client="$(pwd)/docker-finance/client" + # Remove previous alias + if grep "^${_alias}" "$aliases" &>/dev/null; then + sed -i "/^${_alias}/d" "$aliases" + unalias docker-finance + fi + # Set new alias + echo "${_alias}'${_client}/docker.bash'" >>"$aliases" + # Set bash completion + _completion="${_client}/src/docker/completion.bash" + if [ ! -f "$_completion" ]; then + echo "WARNING: bash completion not found" >&2 + else + if ! grep "^source '${_completion}'" "$aliases" &>/dev/null; then + echo "source '${_completion}'" >>"$aliases" + fi + fi + # Make it so + source "$aliases" && echo "SUCCESS: installation complete" + } if ! test -f "$bashrc" || ! hash bash &>/dev/null; then - echo "FATAL: unsupported bash installation" + echo "FATAL: unsupported bash installation" >&2 else if [[ ! -z "$SHELL" && "$SHELL" =~ bash ]]; then if [ ! -f "$aliases" ]; then @@ -275,14 +301,31 @@ Supported blockchains (independent of wallet type): aliases="$bashrc" fi fi - if git clone https://gitea.com/EvergreenCrypto/docker-finance; then - if ! grep -E "^alias docker-finance=" "$aliases" &>/dev/null; then - echo "alias docker-finance='$(pwd)/docker-finance/client/docker.bash archlinux/$(whoami):latest'" >>"$aliases" - source "$aliases" + if hash git &>/dev/null; then + if [ -d docker-finance ]; then + if pushd docker-finance &>/dev/null; then + if ! git pull --tags; then + echo "FATAL: docker-finance repo not pulled" >&2 + else + popd &>/dev/null + docker-finance::install + fi + popd &>/dev/null + else + echo "FATAL: docker-finance repo not found" >&2 + fi + else + if ! git clone https://gitea.com/EvergreenCrypto/docker-finance; then + echo "FATAL: docker-finance repo not cloned" >&2 + else + docker-finance::install + fi fi + else + echo "FATAL: git not found" >&2 fi else - echo "FATAL: unsupported bash environment" + echo "FATAL: unsupported bash environment" >&2 fi fi ``` @@ -300,16 +343,22 @@ Supported blockchains (independent of wallet type): 5. **Generate client/container environment** (see [Environment Generation](#environment-generation) for details): ```bash - docker-finance gen + docker-finance archlinux/${USER}:default gen ``` -6. **Build the image and bring up container**: +6. **Build the image**: ```bash - docker-finance build type=default && docker-finance up + docker-finance archlinux/${USER}:default build type=default ``` - > See `docker-finance build help` for build options (such as smaller, faster builds) + > See `docker-finance archlinux/${USER}:default build help` for build options (such as smaller, faster builds) -7. **You're inside!** See [How do I use it?](#how-do-i-use-it) for next steps. +7. **Bring up the container**: + ```bash + docker-finance archlinux/${USER}:default up + ``` + > You can use tab completion for all commands available to this built image + +8. **You're inside!** See [How do I use it?](#how-do-i-use-it) for next steps. ### Environment Generation @@ -320,7 +369,7 @@ In terms of configuration, the client (host) has the following files: 2. The [Client (Host) Custom Dockerfile](#client-host-custom-dockerfile) (client only) 3. The [Client/Container Superscript](#clientcontainer-superscript) (client/container) -You'll create these files (and more) when running `docker-finance gen`, as seen below. +You'll create these files (and more) when running client (host) command `gen`, as seen below. > Tip: client scope can be considered an OOP class which inherits the container as a protected class, with the [Client/Container Superscript](#clientcontainer-superscript) binding them. @@ -335,13 +384,13 @@ When running `gen`, you'll see the following: Generates the client (host) configuration file (see the [Client (Host) Configuration File](#client-host-configuration) for details). - You can use the generated defaults but make sure your directory layout matches accordingly - - To easily edit this configuration file after `gen` is complete, run `docker-finance edit type=env` + - To easily edit this configuration file after `gen` is complete, run client (host) command `edit type=env` > *Generating new custom (optional) Dockerfile* Generates custom Dockerfile. Do as you wish; install your own container packages, etc. (see the [Client (Host) Custom Dockerfile](#client-host-custom-dockerfile) for details). - - To easily edit this configuration file after `gen` is complete, run `docker-finance edit type=build` + - To easily edit this configuration file after `gen` is complete, run client (host) command `edit type=build` --- @@ -412,7 +461,7 @@ The client (host) configuration file: - consists solely of variables in the format `DOCKER_FINANCE_VARIABLE=value` and is used by both Docker and `docker-finance` - default template variables can be found in [gen.bash](client/docker-finance.d/client/env/gen.bash), as described below -After `gen` is complete, you can edit this file with the client (host) command: `docker-finance edit type=env` (see [Client (Host) Command Format](#client-host-command-format)). +After `gen` is complete, you can edit this file with the client (host) command: `edit type=env` (see [Client (Host) Command Format](#client-host-command-format)). > DOCKER_FINANCE_CLIENT_CONF @@ -564,7 +613,7 @@ The client (host) custom Dockerfile: - format consists of `username@hostname` where `username` is your host username and `hostname` is your machine's hostname - default generated templates can be found [here](client/docker-finance.d/client/Dockerfiles) -After `gen` is complete, you can edit this file with the client (host) command: `docker-finance edit type=build` (see [Client (Host) Command Format](#client-host-command-format)). +After `gen` is complete, you can edit this file with the client (host) command: `edit type=build` (see [Client (Host) Command Format](#client-host-command-format)). --- @@ -580,7 +629,7 @@ See the in-file comments for further documentation: - [superscript.bash.in](client/docker-finance.d/container/shell/superscript.bash.in) -After `gen` is complete, you can edit this file with the client (host) command: `docker-finance edit type=shell` (see [Client (Host) Command Format](#client-host-command-format)). +After `gen` is complete, you can edit this file with the client (host) command: `edit type=shell` (see [Client (Host) Command Format](#client-host-command-format)). --- @@ -660,19 +709,19 @@ Where: For a complete list of commands and usage help: ```bash -${DOCKER_FINANCE_CLIENT_REPO}/client/docker.bash archlinux/$(whoami):latest help +${DOCKER_FINANCE_CLIENT_REPO}/client/docker.bash archlinux/${USER}:default help ``` Or, if the [Installation](#installation) alias was properly created: ```bash -docker-finance help +docker-finance archlinux/${USER}:default help ``` You can also view the help usage of, for example, the `edit` command: ```bash -docker-finance edit help +docker-finance archlinux/${USER}:default edit help ``` --- @@ -865,7 +914,7 @@ Before sending a pull request: - Regarding client configuration, Docker volumes aren't used because of chicken-or-the-egg problem (among other reasons). `docker-finance` needs the client environment *before* building the Docker image and spawning the subsequent container (which would rely on volumes). - As described in [Mostly-Unified CLI](#mostly-unified-cli), to use a developer version of the `finance` image (not a `dev-tools` image), simply build and tag a new `finance` image with `dev` (or whatever you see fit), and reset the `docker-finance` alias at your discretion. -- Run `DOCKER_FINANCE_DEBUG=true docker-finance [args]` to debug *before* the [Client (Host) Configuration File](#client-host-configuration) file is read. +- Run `DOCKER_FINANCE_DEBUG=true docker-finance [args]` to debug *before* the [Client (Host) Configuration File](#client-host-configuration) file is read. - The `.C` files you see in the repository are ROOT.cern macro files, not C-language files. ## How do I connect?