forked from EvergreenCrypto/docker-finance
Adds bitcoin building plugin and finance image build dependencies. See the code documentation in this commit for details.
342 lines
10 KiB
Bash
Executable File
342 lines
10 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# docker-finance | modern accounting for the power-user
|
|
#
|
|
# Copyright (C) 2025 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 <https://www.gnu.org/licenses/>.
|
|
|
|
#
|
|
# NOTES:
|
|
#
|
|
# This plugin provides a rudimentary clone/pull/build process that
|
|
# adheres to the expectations from the container-side bitcoin plugin.
|
|
#
|
|
# The only requirement for this plugin is that build dependencies
|
|
# are installed on your existing/running image (which is assumed to
|
|
# have also been built with the `root` module enabled):
|
|
#
|
|
# 1. Uncomment plugin's image build requirements:
|
|
#
|
|
# $ dfi <platform/user:tag> edit type=build
|
|
#
|
|
# 2. Build/re-build your image with `root` module:
|
|
#
|
|
# $ dfi <platform/user:tag> build type=default
|
|
#
|
|
# If you do bitcoin development on your client (host) and prefer to
|
|
# use your own build process, you can skip the above requirements and,
|
|
# instead, ensure the following:
|
|
#
|
|
# 1. Your bitcoin repository is dropped into your client-side shared
|
|
# directory:
|
|
#
|
|
# $DOCKER_FINANCE_CLIENT_SHARED
|
|
#
|
|
# The expected path by the container-side plugin will be in your
|
|
# container-side shared directory:
|
|
#
|
|
# "${DOCKER_FINANCE_CONTAINER_SHARED}"/bitcoin
|
|
#
|
|
# To see or edit your shared client/container path prior to
|
|
# running this (or the container's) plugin, run the following:
|
|
#
|
|
# $ dfi <platform/user:tag> edit type=env
|
|
#
|
|
# 2. Bitcoin's libraries are built as a shared (when possible) and
|
|
# should continue to remain within the repo's build directory,
|
|
# prior to running the container-side `root` bitcoin plugin.
|
|
#
|
|
|
|
#
|
|
# "Libraries"
|
|
#
|
|
|
|
[ -z "$DOCKER_FINANCE_CLIENT_REPO" ] && exit 1
|
|
source "${DOCKER_FINANCE_CLIENT_REPO}/client/src/docker/lib/lib_docker.bash" || exit 1
|
|
|
|
[[ -z "$global_platform" || -z "$global_arg_delim_1" || -z "$global_user" || -z "$global_tag" ]] && lib_utils::die_fatal
|
|
instance="${global_platform}${global_arg_delim_1}${global_user}:${global_tag}"
|
|
|
|
# Initialize "constructor"
|
|
# NOTE: "constructor" only needed if calling library directly
|
|
lib_docker::docker "$instance" || lib_utils::die_fatal
|
|
|
|
#
|
|
# Implementation
|
|
#
|
|
|
|
# WARNING: *MUST* be synced with image (assuming Arch Linux finance image)
|
|
declare -r plugin_bitcoin_deps=("boost" "capnproto" "cmake" "db")
|
|
|
|
# WARNING: *MUST* be synced with container's plugin implementation
|
|
[ -z "$DOCKER_FINANCE_CONTAINER_SHARED" ] && lib_utils::die_fatal
|
|
declare -r plugin_bitcoin_path="${DOCKER_FINANCE_CONTAINER_SHARED}/bitcoin"
|
|
|
|
function bitcoin::__parse_args()
|
|
{
|
|
[ -z "$global_usage" ] && lib_utils::die_fatal
|
|
[ -z "$global_arg_delim_1" ] && lib_utils::die_fatal
|
|
[ -z "$global_arg_delim_2" ] && lib_utils::die_fatal
|
|
|
|
local -r _default_arg_remote="https://github.com/bitcoin/bitcoin"
|
|
local -r _default_arg_branch="master"
|
|
local -r _default_arg_cmake="-DBUILD_BITCOIN_BIN=OFF -DBUILD_CLI=OFF -DBUILD_DAEMON=OFF -DBUILD_TESTS=OFF -DBUILD_UTIL=OFF -DBUILD_WALLET_TOOL=OFF -DINSTALL_MAN=OFF -DSECP256K1_BUILD_TESTS=OFF -DSECP256K1_BUILD_EXHAUSTIVE_TESTS=OFF -DBUILD_KERNEL_LIB=ON -DBUILD_SHARED_LIBS=ON"
|
|
|
|
# Re-seat global usage
|
|
local _global_usage
|
|
_global_usage="$global_usage plugins repo${global_arg_delim_1}$(basename $0)"
|
|
declare -r _global_usage
|
|
|
|
local -r _usage="
|
|
\e[32mDescription:\e[0m
|
|
|
|
Build bitcoin libraries for \`root\` container-side plugin.
|
|
|
|
\e[32mUsage:\e[0m
|
|
|
|
$ $_global_usage <get | build | clean> [remote${global_arg_delim_2}<remote>] [branch${global_arg_delim_2}<branch>] [cmake${global_arg_delim_2}<cmake>]
|
|
|
|
\e[32mArguments:\e[0m
|
|
|
|
Git remote to get; default:
|
|
|
|
remote${global_arg_delim_2}\"$_default_arg_remote\"
|
|
|
|
Git branch to build from; default:
|
|
|
|
branch${global_arg_delim_2}\"$_default_arg_branch\"
|
|
|
|
CMake build options; default:
|
|
|
|
cmake${global_arg_delim_2}\"$_default_arg_cmake\"
|
|
|
|
\e[32mExamples:\e[0m
|
|
|
|
\e[37;2m# Get from default\e[0m
|
|
$ $_global_usage get
|
|
|
|
\e[37;2m# Get from given remote 'https://my.custom.remote/bitcoin'\e[0m
|
|
$ $_global_usage get remote${global_arg_delim_2}\"https://my.custom.remote/bitcoin\"
|
|
|
|
\e[37;2m# Build default branch\e[0m
|
|
$ $_global_usage build
|
|
|
|
\e[37;2m# Checkout and build given branch\e[0m
|
|
$ $_global_usage build branch=\"my_dev\"
|
|
|
|
\e[37;2m# Checkout and build given commit\e[0m
|
|
$ $_global_usage build branch=\"b30262dcaa28c40a0a5072847b7194b3db203160\"
|
|
|
|
\e[37;2m# Build given branch with custom CMake options\e[0m
|
|
$ $_global_usage build branch=\"my_dev\" cmake${global_arg_delim_2}\"-DBUILD_BITCOIN_BIN=ON -DBUILD_CLI=ON -DBUILD_DAEMON=ON -DBUILD_TESTS=ON -DBUILD_UTIL=ON -DBUILD_WALLET_TOOL=ON -DINSTALL_MAN=ON -DSECP256K1_BUILD_TESTS=ON -DSECP256K1_BUILD_EXHAUSTIVE_TESTS=ON -DBUILD_KERNEL_LIB=ON -DBUILD_SHARED_LIBS=ON\"
|
|
|
|
\e[37;2m# Clean entire build directory\e[0m
|
|
$ $_global_usage clean
|
|
"
|
|
|
|
[ $# -eq 0 ] && lib_utils::die_usage "$_usage"
|
|
|
|
[[ ! "$1" =~ ^get$|^build$|^clean$ ]] \
|
|
&& lib_utils::die_usage "$_usage" \
|
|
|| declare -gr plugin_arg_cmd="$1"
|
|
|
|
for _arg in "${@:2}"; do
|
|
[[ ! "$_arg" =~ ^remote${global_arg_delim_2} ]] \
|
|
&& [[ ! "$_arg" =~ ^branch${global_arg_delim_2} ]] \
|
|
&& [[ ! "$_arg" =~ ^cmake${global_arg_delim_2} ]] \
|
|
&& lib_utils::die_usage "$_usage"
|
|
done
|
|
|
|
for _arg in "${@:2}"; do
|
|
local _key="${_arg%${global_arg_delim_2}*}"
|
|
local _len="$((${#_key} + 1))"
|
|
|
|
if [[ "$_key" =~ ^remote$ ]]; then
|
|
local _arg_remote="${_arg:${_len}}"
|
|
[ -z "$_arg_remote" ] && lib_utils::die_usage "$_usage"
|
|
fi
|
|
|
|
if [[ "$_key" =~ ^branch$ ]]; then
|
|
local _arg_branch="${_arg:${_len}}"
|
|
[ -z "$_arg_branch" ] && lib_utils::die_usage "$_usage"
|
|
fi
|
|
|
|
if [[ "$_key" =~ ^cmake$ ]]; then
|
|
local _arg_cmake="${_arg:${_len}}"
|
|
[ -z "$_arg_cmake" ] && lib_utils::die_usage "$_usage"
|
|
fi
|
|
done
|
|
|
|
# Arg: get
|
|
if [[ "$plugin_arg_cmd" =~ ^get$ ]]; then
|
|
if [[ ! -z "$_arg_branch" || ! -z "$_arg_cmake" ]]; then
|
|
lib_utils::die_usage "$_usage"
|
|
fi
|
|
|
|
# Arg: remote
|
|
if [ -z "$_arg_remote" ]; then
|
|
_arg_remote="$_default_arg_remote"
|
|
fi
|
|
declare -gr plugin_arg_remote="$_arg_remote"
|
|
lib_utils::print_info "Using remote: ${_arg_remote}"
|
|
fi
|
|
|
|
# Arg: build
|
|
if [[ "$plugin_arg_cmd" =~ ^build$ ]]; then
|
|
if [[ ! -z "$_arg_remote" ]]; then
|
|
lib_utils::die_usage "$_usage"
|
|
fi
|
|
|
|
# Arg: branch
|
|
if [ -z "$_arg_branch" ]; then
|
|
_arg_branch="$_default_arg_branch"
|
|
fi
|
|
declare -gr plugin_arg_branch="$_arg_branch"
|
|
lib_utils::print_info "Using branch: ${plugin_arg_branch}"
|
|
|
|
# Arg: cmake
|
|
if [ -z "$_arg_cmake" ]; then
|
|
_arg_cmake="$_default_arg_cmake"
|
|
fi
|
|
declare -gr plugin_arg_cmake="$_arg_cmake"
|
|
lib_utils::print_info "Using CMake options: ${plugin_arg_cmake}"
|
|
fi
|
|
|
|
# Arg: clean
|
|
if [[ "$plugin_arg_cmd" =~ ^clean$ ]]; then
|
|
if [[ ! -z "$_arg_remote" || ! -z "$_arg_branch" || ! -z "$_arg_cmake" ]]; then
|
|
lib_utils::die_usage "$_usage"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
function bitcoin::__getter()
|
|
{
|
|
[ -z "$plugin_arg_remote" ] && lib_utils::die_fatal
|
|
[ -z "$plugin_bitcoin_path" ] && lib_utils::die_fatal
|
|
|
|
lib_docker::exec "if [ ! -d $plugin_bitcoin_path ]; then git clone $plugin_arg_remote $plugin_bitcoin_path ; fi" \
|
|
|| lib_utils::die_fatal "Could not clone '${plugin_arg_remote}' to '${plugin_bitcoin_path}'"
|
|
|
|
lib_docker::exec "pushd $plugin_bitcoin_path 1>/dev/null && git pull $plugin_arg_remote && popd 1>/dev/null" \
|
|
|| lib_utils::die_fatal "Could not pull '${plugin_arg_remote}' to '${plugin_bitcoin_path}'"
|
|
}
|
|
|
|
function bitcoin::__builder()
|
|
{
|
|
#
|
|
# Ensure dependencies
|
|
#
|
|
|
|
local -r _no_deps="Build dependencies not found!
|
|
|
|
Did you uncomment them with:
|
|
|
|
\t\$ dfi $instance edit type=build
|
|
|
|
and then re-build your image with:
|
|
|
|
\t\$ dfi $instance build type=<type>"
|
|
|
|
# NOTE: *MUST* be synced with end-user Dockerfile (`edit type=build`)
|
|
# TODO: not ideal, would prefer runtime dependency pulling but that has drawbacks as well
|
|
[ -z "${plugin_bitcoin_deps[*]}" ] && lib_utils::die_fatal
|
|
lib_docker::exec "pacman -Q ${plugin_bitcoin_deps[*]}" | grep "^error: package" \
|
|
&& lib_utils::die_fatal "$_no_deps"
|
|
|
|
#
|
|
# Execute build
|
|
#
|
|
|
|
[ -z "$plugin_arg_cmake" ] && lib_utils::die_fatal
|
|
[ -z "$plugin_bitcoin_path" ] && lib_utils::die_fatal
|
|
|
|
lib_docker::exec "pushd $plugin_bitcoin_path 1>/dev/null && git checkout $plugin_arg_branch && popd 1>/dev/null" \
|
|
|| lib_utils::die_fatal "Could not checkout '${plugin_arg_branch}'"
|
|
|
|
lib_docker::exec "cmake $plugin_arg_cmake -B ${plugin_bitcoin_path}/build $plugin_bitcoin_path" \
|
|
|| lib_utils::die_fatal "Could not prepare build with given options"
|
|
|
|
lib_docker::exec "cmake --build ${plugin_bitcoin_path}/build -j$(nproc)" \
|
|
|| lib_utils::die_fatal "Could not build"
|
|
|
|
lib_utils::print_info "$(lib_docker::exec "find ${plugin_bitcoin_path} -name libbitcoinkernel.so")"
|
|
}
|
|
|
|
function bitcoin::__cleaner()
|
|
{
|
|
[ -z "$plugin_bitcoin_path" ] && lib_utils::die_fatal
|
|
local -r _build="${plugin_bitcoin_path}/build"
|
|
|
|
lib_utils::print_info "Removing '${_build}'"
|
|
lib_docker::exec "rm -fr $_build" || lib_utils::die_fatal "Could not delete= '${_build}'"
|
|
}
|
|
|
|
#
|
|
# Facade
|
|
#
|
|
|
|
function bitcoin::get()
|
|
{
|
|
lib_utils::print_info "Getting repository"
|
|
bitcoin::__getter
|
|
}
|
|
|
|
function bitcoin::build()
|
|
{
|
|
lib_utils::print_info "Building repository"
|
|
bitcoin::__builder
|
|
}
|
|
|
|
function bitcoin::clean()
|
|
{
|
|
lib_utils::print_info "Cleaning repository"
|
|
bitcoin::__cleaner
|
|
}
|
|
|
|
function main()
|
|
{
|
|
bitcoin::__parse_args "$@"
|
|
|
|
# Ensure running instance
|
|
local -r _no_instance="Did you start a running instance?
|
|
|
|
Run the following in a separate shell:
|
|
|
|
\t$ dfi $instance up"
|
|
|
|
lib_docker::exec "" || lib_utils::die_fatal "$_no_instance"
|
|
|
|
[ -z "$plugin_arg_cmd" ] && lib_utils::die_fatal
|
|
case "$plugin_arg_cmd" in
|
|
get)
|
|
bitcoin::get
|
|
;;
|
|
build)
|
|
bitcoin::build
|
|
;;
|
|
clean)
|
|
bitcoin::clean
|
|
;;
|
|
*)
|
|
lib_utils::die_fatal "Not implemented"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
main "$@"
|
|
|
|
# vim: sw=2 sts=2 si ai et
|