#!/usr/bin/env bash #/############################################################################## # # \file setup-omdl.bash # # \author Roy Allen Sutton <royasutton@hotmail.com>. # \date 2016-2025 # # \copyright # # This file is part of [omdl] (https://github.com/royasutton/omdl), # an OpenSCAD mechanical design library. # # The \em omdl is free software; you can redistribute it and/or modify # it under the terms of the [GNU Lesser General Public License] # (http://www.gnu.org/licenses/lgpl.html) as published by the Free # Software Foundation; either version 2.1 of the License, or (at # your option) any later version. # # The \em omdl 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with the \em omdl; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA; or see <http://www.gnu.org/licenses/>. # ###############################################################################/ declare base_path="${0%/*}" declare base_name="${0##*/}" declare root_name="${base_name%.*}" declare work_path="${PWD}" declare conf_file="${root_name}.conf" declare kernel=$(uname -s) declare sysname=${kernel%%-*} # verify minimum bash version if [[ $BASH_VERSINFO -lt 4 ]] ; then echo "Bash version is $BASH_VERSION. Version 4 or greater required. aborting..." exit 1 fi ############################################################################### # global variables ############################################################################### declare skip_check="no" declare skip_prep="no" declare skip_toolchain="no" declare local_toolchain="no" declare apt_cyg_path declare apt_get_opts="--verbose-versions" declare git_fetch_opts="--verbose" declare repo_url_apt_cyg="https://github.com/transcode-open/apt-cyg" declare repo_url="https://github.com/royasutton/omdl" declare repo_branch="master" declare repo_branch_list declare setup_amu_url="https://git.io/setup-amu.bash" declare cache_install="no" declare repo_cache_root="cache" declare scopes_exclude="db_autotest" declare make_opts_add="generate_latex=" declare commands # variables map: ( "variable-key" "description" "example-value" ) declare -i conf_file_vw=3 declare -a conf_file_va=( "skip_check" "skip system prerequisites check" "$skip_check" "skip_prep" "skip source preparation" "$skip_prep" "skip_toolchain" "skip toolchain preparation" "$skip_toolchain" "local_toolchain" "install design flow tools to local system" "$local_toolchain" "apt_cyg_path" "path to apt-cyg" "/usr/local/bin/apt-cyg" "apt_get_opts" "apt get options" "$apt_get_opts" "git_fetch_opts" "git fetch options" "$git_fetch_opts" "repo_url_apt_cyg" "apt-cyg git repo url (can be local path)" "$repo_url_apt_cyg" "repo_url" "git repo url (can be local path)" "$repo_url" "repo_branch" "git repo branch or tag" "$repo_branch" "repo_branch_list" "git repo branch and/or tag list" "master develop v0.5 v0.6.1" "setup_amu_url" "url to setup-amu.bash script" "$setup_amu_url" "cache_install" "install to cache" "$cache_install" "repo_cache_root" "cache root directory path" "$repo_cache_root" "scopes_exclude" "omdl scope exclusions" "$scopes_exclude" "make_opts_add" "make option additions" "$make_opts_add" "commands" "commands to run with each invocation" "--branch master --install --template my_project" ) # derived variables declare packages declare packages_installed declare packages_missing declare setup_amu_yes declare repo_cache_apt_cyg declare repo_cache declare build_dir declare cache_prefix declare -a make_opts ############################################################################### # message printing ############################################################################### function print_m() { local nl local es local -i rn=1 local ws=' ' local ns="${ws}" case $1 in -j) ;; -J) print_m -j -n -r ${#root_name} ' ' -j ' ' ; shift 1 ;; *) echo -n ${root_name}: ;; esac while [[ $# -gt 0 ]] ; do case $1 in -n) nl=true ;; -e) es=true ;; -E) es='' ;; -j) ns='' ;; -l) echo ; ;; -r) rn=$2 ; shift 1 ;; -s) ws="$2" ; shift 1 ;; *) while ((rn > 0)) do if [[ -z "$es" ]] ; then echo -n -E "${ns}${1}" else echo -n -e "${ns}${1}" fi ns='' let rn-- done ns="${ws}" rn=1 ;; esac shift 1 done [[ -z "$nl" ]] && echo return } function print_hb () { local tput=$(which tput 2>/dev/null) local cols=80 [[ -n "$tput" ]] && cols=$(${tput} cols) print_m -j -r ${cols} ${1:-#} } function print_h1 () { print_hb "#" print_m -j "#" -l -j "#" $* -l -j "#" print_hb "#" } function print_h2 () { print_hb "=" print_m -j $* print_hb "=" } function exit_vm () { local ev=${1:-0} shift 1 print_m $* "(" -j ${ev} -j ")" print_m "exiting..." exit ${ev} } ############################################################################### # os dependent functions ############################################################################### #------------------------------------------------------------------------------ # configuration: # (1) prerequisite package list #------------------------------------------------------------------------------ function update_prerequisite_list() { print_m "${FUNCNAME} begin" local packages_Common local packages_Linux local packages_CYGWIN_NT packages_Common=" bash wget git make unzip openscad " packages_Linux=" " packages_CYGWIN_NT=" " case "${sysname}" in Linux) packages="${packages_Common} ${packages_Linux}" ;; CYGWIN_NT) packages="${packages_Common} ${packages_CYGWIN_NT}" ;; *) exit_vm 1 "Configuration for [$sysname] required." ;; esac print_m "${FUNCNAME} end" } #============================================================================== # Linux #============================================================================== function prerequisite_check.Linux() { dpkg-query --no-pager --show --showformat='${Status}\n' $1 2>/dev/null | grep -q "install ok installed" && return 0 return 1 } function prerequisites_status.Linux() { dpkg-query --no-pager --show $* } function prerequisites_install.Linux() { print_m "apt-get install options: [${apt_get_opts}]" if ! sudo apt-get install ${apt_get_opts} $* ; then exit_vm 1 "Install failed." fi return 0 } function prerequisite_install_openscad.Linux() { local pkg="$1" function setup_repository(){ case "$(lsb_release -si)" in Ubuntu) local repo="deb https://download.opensuse.org/repositories/home:/t-paul/x$(lsb_release -si)_$(lsb_release -sr)/ ./" ;; Debian) local repo="deb https://download.opensuse.org/repositories/home:/t-paul/$(lsb_release -si)_$(lsb_release -sr)/ ./" ;; *) exit_vm 1 "Configuration for [$(lsb_release -si)] required." ;; esac local name="openscad-development-snapshots" local desc="OpenSCAD development snapshots" local rkey="https://files.openscad.org/OBS-Repository-Key.pub" local keyf="5F4A 8A2C 8BB1 1716 F294 82BB 75F3 214F 30EB 8E08" local list="/etc/apt/sources.list.d/${name}.list" local update # setup repository key print_m "repository: [${desc}]" print_m "checking for repository source key..." if [[ -n $(apt-key finger | grep "$keyf") ]] ; then print_m "key found." else print_m "key not found, retreaving..." wget --quiet --output-document - "$rkey" | sudo apt-key add - update="true" fi # setup repository source file print_m "checking for source file: [$list]..." if [[ -f $list ]] ; then print_m "source file exists." else print_m "source file not found, adding..." echo "$repo" | sudo tee $list update="true" fi # resynchronize package index files if [[ "$update" == "true" ]] ; then print_m "resynchronizing package index files..." sudo apt-get --quiet update else print_m "package index resynchronization not required." fi } print_m "exception install: [${pkg}]..." # development snapshots repository only required for openscad-nightly if [[ "${pkg}" == "openscad-nightly" ]] ; then print_m "setting up repository for ${pkg}" setup_repository fi # install package prerequisites_install.${sysname} ${pkg} return 0 } #============================================================================== # Cygwin #============================================================================== function prerequisite_check.CYGWIN_NT() { cygcheck --check-setup --dump-only $1 | tail -1 | grep -q $1 && return 0 return 1 } function prerequisites_status.CYGWIN_NT() { cygcheck --check-setup $* } function prerequisites_install.CYGWIN_NT() { set_apt_cyg_path if ! ${apt_cyg_path} install $* ; then exit_vm 1 "Install failed." fi return 0 } function prerequisite_install_openscad.CYGWIN_NT() { local pkg="$1" function install_openscad(){ local pkg="$1" local ldir="openscad" local lcmd="${pkg}" local arch="x86-32" local fext=".zip" local fpat local surl local path="${repo_cache_root}" local dist="${repo_cache_root}/distrib" local list local -i lcnt=1 local pick local inst case "${pkg}" in openscad) surl="https://files.openscad.org" fpat="OpenSCAD-....\...-${arch}${fext}" ;; openscad-nightly) surl="https://files.openscad.org/snapshots" fpat="OpenSCAD-....\...\...-${arch}${fext}" ;; *) exit_vm 1 "Invalid package name [${pkg}]." ;; esac # download, unpack, create symbolic links, and add to $PATH if [[ -x ${path}/${ldir}/${lcmd}.exe ]] ; then print_m "using ${lcmd} installed in cache." else # determine machine hardware [[ $(arch) == "x86_64" ]] && arch="x86-64" # get list of development snapshots list=$( \ wget --quiet --output-document - ${surl} | grep --only-matching "${fpat}" | sort --uniq | tail --lines=${lcnt} \ ) # downloads distribution(s) print_m "downloading latest [$lcnt] distribution(s):" for f in ${list} ; do print_m "--> $f" if [[ -e "${dist}/${f}" ]] ; then print_m "[${dist}/${f}] exists." else wget --quiet --show-progress --directory-prefix=${dist} "${surl}/${f}" fi pick="$f" done # unpack distribution print_m "unpacking: [$pick]..." unzip -q -u -d ${path} ${dist}/${pick} # set install path for 'picked' snapshot # assumes unpacked directory named: OpenSCAD-* or openscad-* # using head -1 should choose the newest version from the list inst=$(cd ${path} && ls -1d {OpenSCAD-*,openscad-*} 2>/dev/null | head -1) if [[ -z "${inst}" ]] ; then exit_vm 1 "Unable to locate unpacked OpenSCAD distribution." fi # create path symbolic links print_m "creating symbolic links..." ( cd ${path} && ln --force --symbolic --verbose --no-target-directory \ ${inst} ${ldir} ) # iff: openscad-nightly, create command symbolic links if [[ "${lcmd}" == "openscad-nightly" ]] ; then ( cd ${path}/${inst} && ln --force --symbolic --verbose --no-target-directory \ openscad.exe ${lcmd}.exe ) ( cd ${path}/${inst} && ln --force --symbolic --verbose --no-target-directory \ openscad.com ${lcmd}.com ) fi fi # add to path (temporary) print_m "adding (temporary) shell path [${work_path}/${path}/${ldir}]." export PATH="${work_path}/${path}/${ldir}:${PATH}" if [[ -z $(which 2>/dev/null ${lcmd}) ]] ; then exit_vm 1 "Unable to locate or setup requirement: [${lcmd}]." else print_m "confirmed ${lcmd} added to shell path" fi # output and record install note local note="${path}/${lcmd}.readme" if [[ -e ${note} ]] ; then print_m "install note exists: [${note}]." else print_m -j cat << EOF | tee ${note} ##################################################################### ##################################################################### ## ## ## note: ## ## ## ## omdl requires a recent build of OpenSCAD. One has been ## ## downloaded and installed to a cache at: ## ## ## ## PATH=${work_path}/${path}/${ldir}:\${PATH} ## ## ## You should add the location to permanent install to your shell ## ## path if you plan to work with omdl from the command line. ## ## ## ##################################################################### ##################################################################### EOF print_m -j sleep 10 fi } # check to see if ${lcmd} already exists in ${PATH} if [[ -z $(which 2>/dev/null ${lcmd}) ]] ; then print_m "exception install: [${pkg}]..." install_openscad "${pkg}" else print_m "${lcmd} exists in shell path" fi return 0 } function set_apt_cyg_path() { local cmd_name="apt-cyg" local cmd_cache=${repo_cache_apt_cyg}/${cmd_name} if [[ -z "${apt_cyg_path}" ]] ; then apt_cyg_path=$(which 2>/dev/null ${cmd_name} ${cmd_cache} | head -1) if [[ -x "${apt_cyg_path}" ]] ; then print_m "found: ${cmd_name}=${apt_cyg_path}" else print_m "fetching apt-cyg git repository to ${repo_cache_apt_cyg}" repository_update "${repo_url_apt_cyg}" "${repo_cache_apt_cyg}" if [[ -e "${cmd_cache}" ]] ; then [[ ! -x "${cmd_cache}" ]] && chmod --verbose +x ${cmd_cache} apt_cyg_path=$(which 2>/dev/null ${cmd_name} ${cmd_cache} | head -1) print_m "using cached: ${cmd_name}=${apt_cyg_path}" print_m "adding [${apt_cyg_path%/*}] to shell path" PATH=${apt_cyg_path%/*}:${PATH} else exit_vm 1 "Unable to locate or cache ${cmd_name}." fi fi fi return 0 } ############################################################################### # os independent functions ############################################################################### #============================================================================== # general / core #============================================================================== #------------------------------------------------------------------------------ # write configuration file #------------------------------------------------------------------------------ function write_configuration_file() { print_m "${FUNCNAME} begin" local file="$1" ; shift 1 local -i cv_w="$1" ; shift 1 local -a cv_a=( "$@" ) local -i cv_s=$(( ${#cv_a[@]} / ${cv_w} )) local cv_c="#" if [[ -e ${file} ]] then print_m "configuration file ${file} exists... not writting." else print_m "writing ${cv_s} keys to ${file}" print_m > ${file} -j -r 80 ${cv_c} -l \ -j "${cv_c} file: ${file}" -l \ -j -r 80 ${cv_c} cat >> ${file} << EOF # note: # - Do not quote variable names or values. # - Tokenize multi-value lists with ' ' (space-character). # - 'commands' and 'make' options are specified as they are on the command # line, with multi-value lists Tokenized by ',' (comma-character). # - Values can be split across lines using '\\': # commands=\\ # --branch-list master,develop,v0.5,v0.6.1 \\ # --cache --install EOF print_m >> ${file} -j -r 80 ${cv_c} -l -l \ -j ${cv_c} -j -r 79 "=" -l \ -j "${cv_c} Supported Variables" -l \ -j ${cv_c} -j -r 79 "=" -l for ((i = 0; i < $cv_s; i++)) do local kv=${cv_a[$(( $i*$cv_w + 0 ))]} local kd=${cv_a[$(( $i*$cv_w + 1 ))]} local ke=${cv_a[$(( $i*$cv_w + 2 ))]} print_m >> ${file} -j "${cv_c} [::: ${kd^} :::]" -l \ -j "${cv_c} ${kv}=${ke}" -l done print_m >> ${file} -j -r 80 ${cv_c} -l \ -j "${cv_c} eof" -l \ -j -r 80 ${cv_c} fi print_m "${FUNCNAME} end" return 0 } #------------------------------------------------------------------------------ # parse configuration file #------------------------------------------------------------------------------ function parse_configuration_file() { print_m "${FUNCNAME} begin" local file="$1" ; shift 1 local -i cv_w="$1" ; shift 1 local -a cv_a=( "$@" ) local -i cv_s=$(( ${#cv_a[@]} / ${cv_w} )) local -i cv_r=0 function read_key() { local file="$1" local key="$2" # support line gobbling while IFS= read line || [[ -n "$line" ]]; do echo "$line" done < "${file}" | sed -e '/^[[:space:]]*$/d' \ -e '/^[[:space:]]*#/d' \ -e 's/^[[:space:]\t]*//' | grep "${key}=" | tail -1 | sed -e "s/${key}=//" } print_m "checking for ${cv_s} configuration keys" for ((i = 0; i < $cv_s; i++)) do local key=${cv_a[$(( $i*$cv_w + 0 ))]} local cfv printf -v cfv '%s' "$(read_key ${file} $key)" if [[ -n "$cfv" ]] ; then printf -v $key '%s' "$cfv" print_m "setting $key=$cfv" (( ++cv_r )) fi done print_m "read ${cv_r} key values" print_m "${FUNCNAME} end" return 0 } #------------------------------------------------------------------------------ # update build variables #------------------------------------------------------------------------------ function update_build_variables() { print_m "${FUNCNAME} begin" repo_cache_apt_cyg=${repo_cache_root}/apt-cyg repo_cache=${repo_cache_root}/omdl build_dir="build/${repo_branch}/" # make options: output directory make_opts=( output_path=${build_dir} ) # make options: cache directory if [[ "${cache_install}" == "yes" ]] ; then cache_prefix="${work_path}/${repo_cache_root}/local/share/OpenSCAD" make_opts+=( install_prefix_scad=${cache_prefix}/libraries/ install_prefix_html=${cache_prefix}/docs/html/ install_prefix_pdf=${cache_prefix}/docs/pdf/ install_prefix_man=${cache_prefix}/docs/man/ ) fi # make options: scope exclusions if [[ -n "${scopes_exclude}" ]] ; then make_opts+=( scopes_exclude="${scopes_exclude}" ) else make_opts+=( scopes_exclude="" ) fi # make options: other additions if [[ -n "${make_opts_add}" ]] ; then local -a make_opts_add_a # tokenize to array on ',' IFS=',' read -a make_opts_add_a <<< "$make_opts_add" make_opts+=( "${make_opts_add_a[@]}" ) fi print_m "${FUNCNAME} end" } #------------------------------------------------------------------------------ # list prerequisite packages #------------------------------------------------------------------------------ function prerequisites_list() { print_m "${FUNCNAME} begin" update_prerequisite_list print_h2 "[ prerequisites ]" for r in ${packages} ; do print_m -j $r done print_hb "=" print_m "${FUNCNAME} end" } #------------------------------------------------------------------------------ # update prerequisite package status lists #------------------------------------------------------------------------------ function prerequisites_check() { print_m "${FUNCNAME} begin" packages_installed="" packages_missing="" update_prerequisite_list for r in ${packages} ; do if prerequisite_check.${sysname} $r then packages_installed+=" $r" else packages_missing+=" $r" fi done print_m "${FUNCNAME} end" } #------------------------------------------------------------------------------ # show prerequisite package status #------------------------------------------------------------------------------ function prerequisites_status() { print_m "${FUNCNAME} begin" prerequisites_check print_h2 "[ Installed ]" if [[ -n "${packages_installed}" ]] ; then prerequisites_status.${sysname} $packages_installed else print_m -j "installed prerequisite list is empty." fi print_h2 "[ Missing ]" if [[ -n "${packages_missing}" ]] ; then for r in ${packages_missing} ; do print_m -j $r done else print_m -j "missing prerequisite list is empty." print_h2 "[ Asserts ]" prerequisites_assert fi print_hb "=" print_m "${FUNCNAME} end" } #------------------------------------------------------------------------------ # install missing prerequisite packages #------------------------------------------------------------------------------ function prerequisites_install() { print_m "${FUNCNAME} begin" prerequisites_check if [[ -n "${packages_missing}" ]] ; then print_h2 "[ Missing ]" for r in ${packages_missing} ; do print_m -j $r done print_h2 "[ Installing ]" for r in ${packages_missing} ; do print_h2 "installing: [ $r ]" print_m -j $r # exception handler case "$r" in openscad|openscad-nightly) prerequisite_install_openscad.${sysname} $r ;; *) prerequisites_install.${sysname} $r ;; esac done print_hb "=" else print_m "no missing prerequisites." fi print_m "${FUNCNAME} end" return 0 } #------------------------------------------------------------------------------ # assertions on prerequisite packages #------------------------------------------------------------------------------ function prerequisites_assert() { print_m "${FUNCNAME} begin" print_m "${FUNCNAME} end" } #------------------------------------------------------------------------------ # clone or update a Git repository #------------------------------------------------------------------------------ function repository_update() { print_m "${FUNCNAME} begin" local gitrepo="$1" local out_dir="$2" print_m "source: [${gitrepo}]" print_m " cache: [${out_dir}]" # assume 'git' is available, it not report and abort. local git=$(which 2>/dev/null git) if [[ ! -x "${git}" ]] ; then print_m "ERROR: please install git:" case "${sysname}" in Linux) print_m "info: $ sudo apt-get install git" ;; CYGWIN_NT) print_m "info: run Cygwin setup.exe and select Devel/git" ;; *) print_m "info: configuration does not exists for [$sysname]." ;; esac exit_vm 1 fi if [[ -d ${out_dir} ]] ; then if ( cd ${out_dir} 2>/dev/null && git rev-parse 2>/dev/null ) ; then print_m "updating: Git repository cache" ( cd ${out_dir} && ${git} pull ${git_fetch_opts} ) else exit_vm 1 "Directory [${out_dir}] exists and is not a repository." fi else print_m "cloning: Git repository to cache" ${git} clone ${gitrepo} ${out_dir} ${git_fetch_opts} fi if ( cd ${out_dir} 2>/dev/null && git rev-parse 2>/dev/null ) ; then print_m -n "repository description: " ( cd ${out_dir} && git describe --tags --long --dirty ) else exit_vm 1 "Repository update failed." fi print_m "${FUNCNAME} end" return 0 } #------------------------------------------------------------------------------ # remove directory #------------------------------------------------------------------------------ function remove_directory() { print_m "${FUNCNAME} begin" local dir_path="$1" local dir_desc="$2" [[ -n ${dir_desc} ]] && dir_desc+=" " if [[ -x ${dir_path} ]] ; then print_m "removing ${dir_desc}directory [${dir_path}]." rm -rfv ${dir_path} else print_m "${dir_desc}directory [${dir_path}] does not exists." fi print_m "${FUNCNAME} end" } #------------------------------------------------------------------------------ # prepare source for compilation #------------------------------------------------------------------------------ function source_prepare() { print_m "${FUNCNAME} begin" # check for existing source repository if ! ( cd ${repo_cache} 2>/dev/null && git rev-parse 2>/dev/null ) ; then print_m "fetching repository cache." repository_update "${repo_url}" "${repo_cache}" fi # checkout branch if ! ( cd ${repo_cache} && git checkout ${repo_branch} ) ; then exit_vm 1 "Failed to checkout branch [${repo_branch}]." else print_m -n "repository branch description: " ( cd ${repo_cache} && git describe --tags --long --dirty ) fi print_m "${FUNCNAME} end" } #------------------------------------------------------------------------------ # prepare openscad-amu toolchain if required #------------------------------------------------------------------------------ function toolchain_prepare() { print_m "${FUNCNAME} begin" # identify toolchain version specified in omdl Makefile local amu_version=$( \ grep --invert-match '#' ${repo_cache}/Makefile | grep 'AMU_TOOL_VERSION[[:space:]]*:=' | head -1 | awk -F '=' '{print $2}' | sed -s 's/[[:space:]]*//g' \ ) print_m "omdl ${repo_branch} uses openscad-amu ${amu_version}." local test_cmd_name="openscad-seam" local test_cmd_path local cache_cmd_path=${work_path}/${repo_cache_root}/local/bin/${sysname}/${test_cmd_name}-${amu_version} local shell_cmd_path local setup_amu_bash="${repo_cache_root}/setup-amu.bash" local setup_amu_bash_opts local amu_lib_path local amu_tool_prefix # # assume toolchain is available if test command can be found # # check shell path print_m "searching for openscad-amu ${amu_version} in shell path..." shell_cmd_path=$(which 2>/dev/null ${test_cmd_name}-${amu_version} | head -1) if [[ -n ${shell_cmd_path} ]] ; then print_m "--> found [${shell_cmd_path}]" test_cmd_path=${shell_cmd_path} else print_m "--> not found in shell path." # check cache path print_m "searching for openscad-amu ${amu_version} in cache..." if [[ -x ${cache_cmd_path} ]] ; then print_m "--> found [${cache_cmd_path}]" test_cmd_path=${cache_cmd_path} else print_m "--> not found in cache, setting up..." # # setup toolchain # print_m "searching for openscad-amu setup script..." if [[ -x ${setup_amu_bash} ]] ; then print_m "${setup_amu_bash} script exists locally." else print_m "retrieving setup script..." wget --no-verbose --output-document=${setup_amu_bash} ${setup_amu_url} chmod +x ${setup_amu_bash} fi print_h1 "building openscad-amu ${amu_version} from source..." if [[ "${local_toolchain}" == "no" ]] ; then # # setup openscad-amu in temporary cache # print_h1 "installing to temporary cache..." setup_amu_bash_opts="--fetch --reconfigure --cache --branch ${amu_version} ${setup_amu_yes} --install" print_h2 ${setup_amu_bash} ${setup_amu_bash_opts} ${setup_amu_bash} ${setup_amu_bash_opts} || exit_vm 1 "${setup_amu_bash} returned errors." test_cmd_path=${cache_cmd_path} else # # setup openscad-amu on local system # print_h1 "building for install to local system..." setup_amu_bash_opts="--fetch --reconfigure --branch ${amu_version} ${setup_amu_yes} --build" print_h2 ${setup_amu_bash} ${setup_amu_bash_opts} ${setup_amu_bash} ${setup_amu_bash_opts} || exit_vm 1 "${setup_amu_bash} returned errors." print_h1 "installing to local system..." setup_amu_bash_opts="--branch ${amu_version} --sudo --install" print_h2 ${setup_amu_bash} ${setup_amu_bash_opts} ${setup_amu_bash} ${setup_amu_bash_opts} || exit_vm 1 "${setup_amu_bash} returned errors." print_m "searching for openscad-amu ${amu_version} in shell path..." shell_cmd_path=$(which 2>/dev/null ${test_cmd_name}-${amu_version} | head -1) if [[ -n ${shell_cmd_path} ]] ; then print_m "--> found [${shell_cmd_path}]" else exit_vm 1 "--> installed to local system but not found in shell path." fi test_cmd_path=${shell_cmd_path} fi fi fi # # configure toolchain make options # # identify openscad-amu paths if [[ -n ${test_cmd_path} && -x ${test_cmd_path} ]] ; then # get library path amu_lib_path=$( \ ${test_cmd_path} --version --verbose | grep 'lib path' | awk '{print $4}' \ ) # get tool path prefix (add trailing directory slash) amu_tool_prefix=${test_cmd_path%/*}/ else exit_vm 1 "Unable to find or setup ${test_cmd_name}-${amu_version}." fi # configure openscad-amu version make options if [[ -n ${amu_version} && -x ${amu_lib_path} && -x ${amu_tool_prefix} ]] ; then print_m "adding make options for openscad-amu ${amu_version}..." make_opts+=( AMU_TOOL_VERSION=${amu_version} AMU_LIB_PATH=${amu_lib_path} AMU_TOOL_PREFIX=${amu_tool_prefix} ) else for opt in ${make_opts[@]} \ "AMU_TOOL_VERSION=${amu_version}" \ "AMU_LIB_PATH=${amu_lib_path}" \ "AMU_TOOL_PREFIX=${amu_tool_prefix}" do print_m "make option --> $opt" done exit_vm 1 "Unable to update make options for toolchain." fi print_m "${FUNCNAME} end" return 0 } #------------------------------------------------------------------------------ # run make with targets #------------------------------------------------------------------------------ function source_make() { print_m "${FUNCNAME} begin" update_build_variables if [[ "${skip_check}" == "yes" ]] ; then print_m "skipping system prerequisite checks." else print_m "checking system for prerequisites." prerequisites_install fi if [[ "${skip_check}" == "yes" ]] ; then print_m "skipping system prerequisite asserts." else print_m "checking system for prerequisite asserts." prerequisites_assert fi if [[ "${skip_prep}" == "yes" ]] ; then print_m "skipping source preparation." else print_m "preparing source." source_prepare fi if [[ "${skip_toolchain}" == "yes" ]] ; then print_m "skipping toolchain preparation." else print_m "preparing toolchain." toolchain_prepare fi print_hb '+' print_m "building [$*]." print_m "directory:" print_m " [$repo_cache]" print_m "options:" for i in "${make_opts[@]}" $* ; do print_m " [$i]" done print_hb '+' print_m \( cd ${repo_cache} \&\& make "${make_opts[@]}" $* \) ( cd ${repo_cache} && make "${make_opts[@]}" $* ) || exit_vm 1 "make returned error." print_m "${FUNCNAME} end" return 0 } #------------------------------------------------------------------------------ # parse command line arguments (per-branch) #------------------------------------------------------------------------------ function parse_commands_branch() { print_m "${FUNCNAME} begin" while [[ $# -gt 0 ]]; do case $1 in --skip-check) print_h2 "setting: skip prerequisite check" skip_check="yes" ;; --skip-prep) print_h2 "setting: skip source preparation" skip_prep="yes" ;; --skip-toolchain) print_h2 "setting: skip toolchain preparation" skip_toolchain="yes" ;; --local-toolchain) print_h2 "setting: local system toolchain processing" local_toolchain="yes" ;; --list) print_h1 "Listing prerequisites" prerequisites_list ;; --check) print_h1 "Checking for installed prerequisites" prerequisites_status ;; --required) print_h1 "Installing missing prerequisites" prerequisites_install ;; --yes) local opt="--assume-yes" print_h2 "adding: apt-get install option [${opt}]" [[ -n "${apt_get_opts}" ]] && apt_get_opts+=" ${opt}" [[ -z "${apt_get_opts}" ]] && apt_get_opts="${opt}" setup_amu_yes="$1" ;; --no-excludes) print_h2 "Building all scopes; overridding any exclusions" unset scopes_exclude ;; -c|--cache) print_h2 "setting: configure source to install to cache" cache_install="yes" ;; --cache-root) if [[ -z "$2" ]] ; then print_m "syntax: ${base_name} $1 <path>" exit_vm 1 "Missing cache root path." fi repo_cache_root="$2" ; shift 1 print_h2 "setting: cache root path [${repo_cache_root}]" ;; -v|--branch) if [[ -z "$2" ]] ; then print_m "syntax: ${base_name} $1 <name>" exit_vm 1 "Missing repository branch name." fi repo_branch="$2" ; shift 1 print_h2 "setting: source branch [${repo_branch}]" ;; -b|--build) local targets="all" print_h1 "Building omdl: make target=[${targets}]" source_make ${targets} ;; -i|--install) local targets="install" print_h1 "Building omdl: make target=[${targets}]" source_make ${targets} ;; -u|--uninstall) local targets="uninstall" print_h1 "Building omdl: make target=[${targets}]" source_make ${targets} ;; -m|--make) if [[ -z "$2" ]] ; then print_m "syntax: ${base_name} $1 <name1,name2,...>" exit_vm 1 "Missing make target list." fi # get list and tokenize with [,] local targets="${2//,/ }" ; shift 1 print_h1 "Building omdl: make target=[${targets}]" source_make ${targets} ;; --remove) print_h1 "Remove source build directory" update_build_variables remove_directory "${repo_cache}/${build_dir}" "source build" ;; *) exit_vm 1 "Invalid command [$1]." ;; esac shift 1 done print_m "${FUNCNAME} end" } #------------------------------------------------------------------------------ # parse command line arguments (per-repository) #------------------------------------------------------------------------------ function parse_commands_repo() { print_m "${FUNCNAME} begin" local args while [[ $# -gt 0 ]]; do case $1 in --fetch) print_h1 "Updating omdl source cache" update_build_variables repository_update "${repo_url}" "${repo_cache}" ;; -l|--branch-list) if [[ -z "$2" ]] ; then print_m "syntax: ${base_name} $1 <name1,name2,...>" exit_vm 1 "Missing repository branch list." fi # get list and tokenize with [,] repo_branch_list="${2//,/ }" ; shift 1 print_h1 "setting: branch list [${repo_branch_list}]" ;; -h|--help) print_help exit_vm 0 ;; --examples) print_examples exit_vm 0 ;; --info) print_info exit_vm 0 ;; --write-conf) write_configuration_file "${conf_file}" "${conf_file_vw}" "${conf_file_va[@]}" exit_vm 0 ;; # argument is not "per-repository", add to argument list to be # passed to the "per-branch" argument parser *) [[ -n $args ]] && args+=" $1" [[ -z $args ]] && args=$1 ;; esac shift 1 done # # process argument list for each specified repository branch # if [[ -z ${repo_branch_list} ]] ; then # empty list, single branch for command arguments parse_commands_branch $args else # list specified, process command arguments for each branch # check for 'tags' keyword if [[ ${repo_branch_list:0:4} == "tags" ]] ; then # obtain list of tagged releases from git repository # force immediate clone/update of source repository (if needed) update_build_variables # check for source if ! ( cd ${repo_cache} 2>/dev/null && git rev-parse 2>/dev/null ) ; then print_m "fetching repository cache." repository_update "${repo_url}" "${repo_cache}" fi # check for 'tagsN', where 'N' indicates use last 'N' tags. local repo_branch_list_cnt=${repo_branch_list:4} if [[ -z ${repo_branch_list_cnt} ]] ; then repo_branch_list=$( cd ${repo_cache} && git tag ) print_m tag limits = [all] else repo_branch_list=$( cd ${repo_cache} && git tag | tail -${repo_branch_list_cnt} ) print_m tag limits = last [${repo_branch_list_cnt}] fi print_m using tag list = [${repo_branch_list}] fi # handle command set for each branch print_m "${FUNCNAME}.branch-list begin" for tag in ${repo_branch_list} ; do repo_branch="$tag" print_h2 "setting: source branch [${repo_branch}]" print_m $args parse_commands_branch $args done print_m "${FUNCNAME}.branch-list end" fi print_m "${FUNCNAME} end" } #============================================================================== # help, examples, and info #============================================================================== #------------------------------------------------------------------------------ # help #------------------------------------------------------------------------------ function print_help() { print_m -j "${base_name}: (Help)" -l cat << EOF This script attempts to setup the omdl OpenSCAD library. It downloads the source, builds, and installs the library include files and documentation. Detected missing prerequisites are installed prior when possible, including the openscad-amu toolchain. [ branch options ] --skip-check : Skip system prerequisites check. --skip-prep : Skip source preparation (use with care). --skip-toolchain : Skip toolchain preparation. --local-toolchain : Install design flow tools to local system. --list : List prerequisites. --check : Check system for prerequisites. --required : Install missing prerequisites. --yes : Automatic 'yes' to install prompts. --no-excludes : Build all omdl scopes. -c | --cache : Configure source to install to cache. --cache-root : Set the cache root directory. -v | --branch <name> : Use branch 'name' default=(master). -b | --build : Build library documentation. -i | --install : Install library documentation. -u | --uninstall : Uninstall library documentation. -m | --make <list> : Run make with target 'list'. --remove : Remove source build directory. [ repository options ] --fetch : Download/update source repository cache. -l | --branch-list <list> : Iterate over list of repository branches: use: tags for ALL tagged releases. tagsN for last 'N' tagged releases. [ other options ] -h | --help : Show this help message. --examples : Show some examples uses. --info : Show script information. --write-conf : Write example configuration file. NOTES: * See --examples for basic usage examples. * Setup options can be stored in configuration file. Use --write-conf to generate a template with configuration parameters. * The --no-excludes option builds optional library scopes such as some tests, documentation statistics, etc. EOF } #------------------------------------------------------------------------------ # examples #------------------------------------------------------------------------------ function print_examples() { print_m -j "${base_name}: (Examples)" -l cat << EOF (1) Build and install branch v0.9.7 to the OpenSCAD user library path. $ ./setup-omdl.bash --branch v0.9.7 --yes --install (2) Build and install the latest source branch to a local cache. $ ./setup-omdl.bash --cache --branch-list tags1 --yes --install (3) Build and install the latest source branch to the OpenSCAD user library path. $ ./setup-omdl.bash --branch-list tags1 --yes --install (4) Build all scopes and install select tagged release versions, to the OpenSCAD user library path. $ ./setup-omdl.bash --branch-list v0.9.1,v0.9.6,v0.9.7 --no-excludes --install (5) Build all scopes and install all release versions, to the OpenSCAD user library path. $ ./setup-omdl.bash --branch-list tags --no-excludes --install (6) See omdl library documentation. [cache] $ google-chrome cache/local/share/OpenSCAD/docs/html/index.html [OpenSCAD user library] $ (cd cache/omdl; make print-install_prefix_html) $ google-chrome <install_prefix_html>/index.html EOF } #------------------------------------------------------------------------------ # info #------------------------------------------------------------------------------ function print_info() { print_m -j "${base_name}: (Info)" -l cat << EOF package: omdl bug report: royasutton@hotmail.com site url: https://royasutton.github.io/omdl EOF } ############################################################################### ############################################################################### ## ## (main) process command line arguments. ## ############################################################################### ############################################################################### # parse configuration file if [[ -e ${conf_file} ]] ; then print_m "reading configuration file: ${conf_file}" parse_configuration_file "${conf_file}" "${conf_file_vw}" "${conf_file_va[@]}" else print_m "configuration file ${conf_file} does not exists." fi # parse configuration file commands if [[ -n "${commands}" ]] ; then print_m "processing configuration file commands." parse_commands_repo ${commands} fi # parse command line arguments if [[ $# -ne 0 ]] ; then print_m "processing command line arguments." parse_commands_repo $* fi # show help if no command line arguments or configuration file commands if [[ $# == 0 && -z "${commands}" ]] ; then print_help exit_vm 0 fi print_m "done." exit 0 ############################################################################### # eof ###############################################################################