summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAaron Ball <nullspoon@oper.io>2016-12-11 23:51:40 -0700
committerAaron Ball <nullspoon@oper.io>2016-12-11 23:51:40 -0700
commit533cff3fadcf3b4bf2e18fe011459620a2e3b757 (patch)
tree689f3b67524f66656220fc77e363d872b954ef19 /lib
downloadportimg-533cff3fadcf3b4bf2e18fe011459620a2e3b757.tar.gz
portimg-533cff3fadcf3b4bf2e18fe011459620a2e3b757.tar.xz
Initial commit
Includes the GPLv3 license and headers. This version builds a basic composite port filesystem overlay from the specified manifest list. It also provides a very basic file templating system using a pseudo jinja syntax for variables (no conditional support yet). There is also a basic logging library included that outputs standardized log output indirectoy to stdout (to prevent mucking with function return vals).
Diffstat (limited to 'lib')
-rw-r--r--lib/config.sh181
-rw-r--r--lib/log.sh73
-rw-r--r--lib/pkg.sh84
-rw-r--r--lib/port.sh46
-rw-r--r--lib/template.sh46
5 files changed, 430 insertions, 0 deletions
diff --git a/lib/config.sh b/lib/config.sh
new file mode 100644
index 0000000..afc186c
--- /dev/null
+++ b/lib/config.sh
@@ -0,0 +1,181 @@
+#!/usr/bin/env bash
+#
+# Libconfig provides basic global configuration key/value support
+# Copyright (C) 2016 Aaron Ball <nullspoon@oper.io>
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+
+#
+# libconfig
+# ---------
+# Libconfig provides support for a global configuration associative array
+# called 'configs'.
+#
+# This provides an easy way to store configuration data in a unified location.
+# With this data in a predictable unified location, it can easily be dumped and
+# reviewed.
+#
+# This also provides support to easily load single-dimensional delimited
+# configuration files through the load_config_with_delim function. This will
+# populate the global configs associative array with any key-value pairs that
+# are found.
+#
+
+set -u
+
+# Header guard
+if [[ -z ${!configs[@]} && -z ${__configssetup:-} ]]; then
+ # Configs associative array is undefined
+ # Define it along with the global reconstruction string, currently empty.
+ declare -xA configs
+ declare -x __configssetup=''
+elif [[ ! -z ${__configssetup:-} ]]; then
+ # Configs undefined, but reconstruction code was found
+ # Reconstruct using __configssetup
+ # NOTE: This is a terrible hack to work around the bug in bash that disallows
+ # passing of arrays and associative arrays to subshells.
+ eval ${__configssetup}
+fi
+
+
+#
+# Parses the specified file, loading into the global configs associative array,
+# key-value pairs seperated by the specified delimiter. Leading and trailing
+# whitespace is removed to allow for human-friendly indentation. Comments are
+# also supported where the line starts with the common # comment character.
+#
+# Examples:
+#
+# key = value
+# key-two = value2
+#
+# - or -
+#
+# key: value
+# key-two: value2
+#
+# @param file Path to file to parse and load
+# @param delim Delimiter to use for seperating keys and values.
+#
+function load_config_with_delim {
+ [[ -z ${1} ]] && log error "File argument required." && exit 1
+ [[ -z ${2} ]] && log error "Delimiter argument required." && exit 1
+
+ local file=${1}
+ local delim=${2}
+
+ [[ ! -f ${file} ]] && log error "Could not find config '${file}'" && exit 1
+
+ local contents=$(cat ${file} | grep -v '^ *#' | grep -v '^[ ]*$' | sed 's/^ \+//')
+
+ local oldifs=${IFS}
+ export IFS=$'\n'
+ for i in ${contents[@]}; do
+ local key=$(echo ${i} | cut -d "${delim}" -f 1 | sed -e 's/ \+$//' -e 's/["'\'']//g')
+ local val=$(echo ${i} | cut -d "${delim}" -f 2 | sed -e 's/^ \+//' -e 's/["'\'']//g')
+ configs[$key]="${val}"
+ done
+ export IFS=${oldifs}
+}
+
+
+#
+# Dumps the global associative array to stdout. Output format is an
+# alphabetically sorted, space-delimited, aligned table (uses the column command
+# for alignment). Output is cumbersome for computers to parse, but easy to read
+# for humans. Useful for debugging.
+#
+# NOTE: Uses the 'ø' character for column delimiting because it is a very rare
+# character in most languages. If a config key or value contains this
+# character, output may be mangled.
+#
+function dump_configs {
+ # Using something really strange to reduce the chance that we split on a
+ # charcter that exists in a key or value.
+ local delim='ø'
+
+ # Set the table header
+ local header="Key${delim}Value\n---${delim}-----\n"
+ local out=''
+
+ # configs needs to be a global associative array
+ for key in ${!configs[@]}; do
+ out="${out}${key}${delim}${configs[$key]}\n"
+ done
+
+ # Sort the variables
+ out="$(echo -e ${out} | sort)"
+
+ # Output
+ echo -e "\nEnvironment:\n"
+ echo -e "${header}${out}" | column -s ${delim} -t
+ echo
+}
+
+
+#
+# Setter for the global configs data structure.
+#
+# NOTE: It is *highly* recommended to use this function to update values in the
+# global configs associative array because it will regenerate the
+# reconstruction string used for serializing the global assoc array for
+# passing to subshells.
+#
+# @param key Key to set
+# @param val Value to set
+#
+function config_set {
+ local key=${1:-}
+ local val=${2:-}
+
+ [[ -z ${key} ]] && log error "Key argument (1) required." && exit 1
+
+ configs[$key]="${val}"
+
+ # Update the reconstruction string so it has the new value
+ __configssetup=$(declare -p configs)
+}
+
+
+#
+# Getter for the global configs data structure. This function provides a bit of
+# added safety over the bash square bracket query, since this distinguishes
+# between unset and empty and will error if requested key could not be found.
+#
+# @param key Key to get
+#
+function config_get {
+ local key=${1:-}
+
+ [[ -z ${key} ]] && log error "Key argument (1) required." && return 1
+
+ # Iterrate over the keys and return if a matching key is found.
+ #
+ # This is less efficient than just querying for the key using the bash square
+ # bracket construct. However, this provides more flexibility in that if a
+ # variable is not set, it allows us to exit gracefully with a log message
+ # instead of just exiting.
+ # This also allows the code to distinguish between unset and empty. The bash
+ # square bracket functionality does not make this distrinction.
+ for i in ${!configs[@]}; do
+ if [[ ${i} == ${key} ]]; then
+ echo ${configs[$key]}
+ return 0
+ fi
+ done
+
+ log error "Config ${key} is not set."
+ return 1
+}
diff --git a/lib/log.sh b/lib/log.sh
new file mode 100644
index 0000000..26bc5bb
--- /dev/null
+++ b/lib/log.sh
@@ -0,0 +1,73 @@
+#!/usr/bin/env bash
+#
+# Liblog provides basic bash logging support
+# Copyright (C) 2016 Aaron Ball <nullspoon@oper.io>
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+
+
+#
+# Liblog
+# ------
+# This is useful for ensuring log output consistency. All log levels are
+# timestamped. Error logs also include the name of the calling function that
+# triggered the error message.
+#
+# NOTE: Logging outputs to file descriptor 9, which is redirected to STDOUT.
+# This allows functions to log output, while still having an echoed return
+# value without return value conflicts.
+#
+
+# Open additional file descriptor for stdout logging that won't conflict with
+# function return values
+exec 9>&1
+
+
+#
+# Standard logging function. Prints standardized output. Timestamps all
+# messages. Error messages automatically print calling function name.
+#
+# @param level Log level to print (error, warn, debug, info, etc)
+# @param msg Message to log. Escape sequences allowed. Captures all arguments
+# following this param, so multiple messages will be appended.
+#
+function log {
+ local level=${1}
+ shift
+ local msg=${@}
+
+ local d=$(date '+%F %T')
+ local label=''
+
+ if [[ ${level} == 'error' ]]; then
+ label="${d} ERROR Function ${FUNCNAME[1]}: "
+ elif [[ ${level} == 'warn' ]]; then
+ label="${d} WARN "
+ elif [[ ${level} == 'debug' ]]; then
+ label="${d} DEBUG "
+ elif [[ ${level} == 'info' ]]; then
+ label="${d} INFO "
+ fi
+
+ echo -e "${label}${msg}" >&9
+}
+
+
+# Some aliases for easier logging
+function lerror { log error ${@}; }
+function lwarn { log warn ${@}; }
+function ldebug { log debug ${@}; }
+function linfo { log info ${@}; }
+function lfatal { log fatal ${@}; }
diff --git a/lib/pkg.sh b/lib/pkg.sh
new file mode 100644
index 0000000..9c1a5df
--- /dev/null
+++ b/lib/pkg.sh
@@ -0,0 +1,84 @@
+#!/usr/bin/env bash
+#
+# Portimg uses Crux port-like system for creating software deployment images.
+# Copyright (C) 2016 Aaron Ball <nullspoon@oper.io>
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+
+source ${LIBDIR}/log.sh # Logging support
+source ${LIBDIR}/template.sh # Included so each port can use templates
+source ${LIBDIR}/port.sh # Basic port functions
+
+export PORTSDIR=${PORTSDIR:-/usr/ports} # Path to port store
+export PORTTMP='' # Path to the port temp dir
+
+function pkg_download_src {
+ local pkgsrc=${1}
+ shift
+ local src=${@}
+
+ # Download from Pkgfile src spec
+ for file in ${src[@]}; do
+ # If the source file exists locally, just copy from here
+ if [[ -f ${file} ]]; then
+ cp -p ${file} ${pkgsrc}
+ else
+ linfo "Downloading ${file}"
+ download_src ${file} ${pkgsrc}
+ linfo "Extracting $(basename ${file}) to ${pkgsrc}"
+ archive_extract ${pkgsrc}/$(basename ${file}) ${pkgsrc}
+ fi
+ done
+}
+
+
+#
+# TODO: Describe this
+#
+function pkgmk {
+ local port=${1:-}
+
+ local PKG='' # Path to the port pkg dir (binary install dest)
+ local PKGSRC='' # Path to the port src dir
+
+ # Change context to port dir
+ cd ${PORTSDIR}/${port}
+
+ # Include the port Pkgfile
+ source Pkgfile
+
+ # Create the port build and install directory structure
+ PORTTMP=$(mktemp -d /tmp/pkgmk-${port}.XXXX)
+ PKGSRC=${PORTTMP}/src
+ PKG=${PORTTMP}/pkg
+ mkdir -p {${PKGSRC},${PKG}}
+
+ # Download the package source files
+ pkg_download_src "${PKGSRC}" "${src[@]}"
+
+ cd ${PKGSRC}
+
+ # Call the build process if defined
+ if [[ $(type -t pkgbuild) == 'function' ]]; then
+ linfo "Running ${port} build process"
+ pkgbuild
+ return $?
+ else
+ lerror "Port ${port} has no pkgbuild function. Aborting."
+ return 1
+ fi
+
+ return 0
+}
diff --git a/lib/port.sh b/lib/port.sh
new file mode 100644
index 0000000..0797e57
--- /dev/null
+++ b/lib/port.sh
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+#
+# Portimg uses Crux port-like system for creating software deployment images.
+# Copyright (C) 2016 Aaron Ball <nullspoon@oper.io>
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+
+function archive_extract {
+ local src=${1:-}
+ local dest=${2:-}
+
+ local ext=${src##*.}
+
+ if [[ ${ext} == 'tar'
+ || ${ext} == 'gz'
+ || ${ext} == 'tgz'
+ || ${ext} == 'xz'
+ || ${ext} == 'bz2' ]]; then
+ tar -xf ${src} -C ${dest}
+ elif [[ ${ext} == 'zip' ]]; then
+ unzip ${src} -d ${dest}
+ fi
+}
+
+
+function download_src {
+ local uri=${1:-}
+ local destdir=${2:-}
+
+ local localname=$(basename ${uri})
+
+ curl -L -s -k -o "${destdir}/${localname}" "${uri}"
+}
+
diff --git a/lib/template.sh b/lib/template.sh
new file mode 100644
index 0000000..f9fc825
--- /dev/null
+++ b/lib/template.sh
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+#
+# Portimg uses Crux port-like system for creating software deployment images.
+# Copyright (C) 2016 Aaron Ball <nullspoon@oper.io>
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+
+source ${LIBDIR}/config.sh
+
+#
+# Provides *very* basic templating functionality. Interpolates basic jinja
+# variable syntax ( "{{ variable }}" ).
+#
+# @param src Path to template file to interpolate
+# @param dest Destination to copy the interpolated template to
+#
+function template {
+ local src=${1:-}
+ local dest=${2:-}
+
+ local delim=$'\001'
+ local tmp=$(mktemp tmp.template.XXXXXXXX)
+
+ cp -p ${src} ${tmp}
+ for key in ${!configs[@]}; do
+ sed -i "s${delim}{{ ${key} }}${delim}${configs[$key]}${delim}g" ${tmp}
+ done
+
+ # Create parent directory if it doesn't yet exist
+ [[ ! -d $(dirname ${dest}) ]] && mkdir -p $(dirname ${dest})
+
+ # Move the modified version into place
+ mv ${tmp} ${dest}
+}

Generated by cgit