2
0
mirror of https://github.com/bpkg/bpkg synced 2024-11-17 21:26:01 +00:00
bpkg/lib/install/install.sh
brandonocasey 5b707579cb added files array support to install/package.json
updated readme with files entry
moved package.json copy near the start of install
moved directory creation to the start of install
moved getdeps to the start of install
2016-02-27 03:25:03 -05:00

410 lines
9.8 KiB
Bash
Executable File

#!/bin/bash
# Include config rc file if found
CONFIG_FILE="$HOME/.bpkgrc"
[ -f "$CONFIG_FILE" ] && source "$CONFIG_FILE"
## set defaults
if [ ${#BPKG_REMOTES[@]} -eq 0 ]; then
BPKG_REMOTES[0]=${BPKG_REMOTE-https://raw.githubusercontent.com}
BPKG_GIT_REMOTES[0]=${BPKG_GIT_REMOTE-https://github.com}
fi
BPKG_USER="${BPKG_USER:-"bpkg"}"
## check parameter consistency
validate_parameters () {
if [ ${#BPKG_GIT_REMOTES[@]} -ne ${#BPKG_REMOTES[@]} ]; then
mesg='BPKG_GIT_REMOTES[%d] differs in size from BPKG_REMOTES[%d] array'
fmesg=$(printf "$mesg" "${#BPKG_GIT_REMOTES[@]}" "${#BPKG_REMOTES[@]}")
error "$fmesg"
return 1
fi
return 0
}
## outut usage
usage () {
echo "usage: bpkg-install [-h|--help]"
echo " or: bpkg-install [-g|--global] <package>"
echo " or: bpkg-install [-g|--global] <user>/<package>"
}
## format and output message
message () {
if type -f bpkg-term > /dev/null 2>&1; then
bpkg-term color "${1}"
fi
shift
printf " ${1}"
shift
if type -f bpkg-term > /dev/null 2>&1; then
bpkg-term reset
fi
printf ": "
if type -f bpkg-term > /dev/null 2>&1; then
bpkg-term reset
bpkg-term bright
fi
printf "%s\n" "${@}"
if type -f bpkg-term > /dev/null 2>&1; then
bpkg-term reset
fi
}
## output error
error () {
{
message "red" "error" "${@}"
} >&2
}
## output warning
warn () {
{
message "yellow" "warn" "${@}"
} >&2
}
## output info
info () {
local title="info"
if (( "${#}" > 1 )); then
title="${1}"
shift
fi
message "cyan" "${title}" "${@}"
}
## Install a bash package
bpkg_install () {
local pkg=""
local let needs_global=0
declare -a args=( "${@}" )
for opt in "${@}"; do
if [ "-" = "${opt:0:1}" ]; then
continue
fi
pkg="${opt}"
break
done
for opt in "${@}"; do
case "${opt}" in
-h|--help)
usage
return 0
;;
-g|--global)
shift
needs_global=1
;;
*)
if [ "-" = "${opt:0:1}" ]; then
echo 2>&1 "error: Unknown argument \`${1}'"
usage
return 1
fi
;;
esac
done
## ensure there is a package to install
if [ -z "${pkg}" ]; then
usage
return 1
fi
echo
## Check each remote in order
local let i=0
for remote in "${BPKG_REMOTES[@]}"; do
local git_remote=${BPKG_GIT_REMOTES[$i]}
bpkg_install_from_remote "$pkg" "$remote" "$git_remote" $needs_global
if [ "$?" == "0" ]; then
return 0
elif [ "$?" == "2" ]; then
error "fatal error occurred during install"
return 1
fi
i=$((i+1))
done
error "package not found on any remote"
return 1
}
## try to install a package from a specific remote
## returns values:
## 0: success
## 1: the package was not found on the remote
## 2: a fatal error occurred
bpkg_install_from_remote () {
local pkg=$1
local remote=$2
local git_remote=$3
local let needs_global=$4
local cwd=$(pwd)
local url=""
local uri=""
local test_uri=""
local version=""
local status=""
local json=""
local user=""
local name=""
local version=""
local auth_param=""
local let has_pkg_json=1
declare -a local pkg_parts=()
declare -a local remote_parts=()
declare -a local scripts=()
declare -a local files=()
## get version if available
{
OLDIFS="${IFS}"
IFS="@"
pkg_parts=(${pkg})
IFS="${OLDIFS}"
}
if [ ${#pkg_parts[@]} -eq 1 ]; then
version="master"
#info "Using latest (master)"
elif [ ${#pkg_parts[@]} -eq 2 ]; then
name="${pkg_parts[0]}"
version="${pkg_parts[1]}"
else
error "Error parsing package version"
return 1
fi
## split by user name and repo
{
OLDIFS="${IFS}"
IFS='/'
pkg_parts=(${pkg})
IFS="${OLDIFS}"
}
if [ ${#pkg_parts[@]} -eq 1 ]; then
user="${BPKG_USER}"
name="${pkg_parts[0]}"
elif [ ${#pkg_parts[@]} -eq 2 ]; then
user="${pkg_parts[0]}"
name="${pkg_parts[1]}"
else
error "Unable to determine package name"
return 1
fi
## clean up name of weird trailing
## versions and slashes
name=${name/@*//}
name=${name////}
## check to see if remote is raw with oauth (GHE)
if [ "${remote:0:10}" == "raw-oauth|" ]; then
info "Using OAUTH basic with content requests"
OLDIFS="${IFS}"
IFS="|"
local remote_parts=($remote)
IFS="${OLDIFS}"
local token=${remote_parts[1]}
remote=${remote_parts[2]}
auth_param="-u $token:x-oauth-basic"
uri="/${user}/${name}/raw/${version}"
## If git remote is a URL, and doesn't contain token information, we
## inject it into the <user>@host field
if [[ "$git_remote" == https://* ]] && [[ "$git_remote" != *x-oauth-basic* ]] && [[ "$git_remote" != *${token}* ]]; then
git_remote=${git_remote/https:\/\//https:\/\/$token:x-oauth-basic@}
fi
else
uri="/${user}/${name}/${version}"
fi
## clean up extra slashes in uri
uri=${uri/\/\///}
info "Install $uri from remote $remote [$git_remote]"
## Ensure remote is reachable
## If a remote is totally down, this will be considered a fatal
## error since the user may have intended to install the package
## from the broken remote.
{
status=$(curl $auth_param -s "${remote}" -w '%{http_code}' -o /dev/null)
if [ "0" != "$?" ] || (( status >= 400 )); then
error "Remote unreachable: $remote"
return 2
fi
}
## build url
url="${remote}${uri}"
repo_url=$git_remote/$user/$name.git
## determine if `package.json' exists at url
{
status=$(curl $auth_param -sL "${url}/package.json?`date +%s`" -w '%{http_code}' -o /dev/null)
if [ "0" != "$?" ] || (( status >= 400 )); then
warn "package.json doesn't exist"
has_pkg_json=0
# check to see if there's a Makefile. If not, this is not a valid package
status=$(curl $auth_param -sL "${url}/Makefile?`date +%s`" -w '%{http_code}' -o /dev/null)
if [ "0" != "$?" ] || (( status >= 400 )); then
warn "Makefile not found, skipping remote: $url"
return 1
fi
fi
}
## read package.json
json=$(curl $auth_param -sL "${url}/package.json?`date +%s`")
if (( 1 == $has_pkg_json )); then
## get package name from `package.json'
name="$(
echo -n ${json} |
bpkg-json -b |
grep 'name' |
awk '{ $1=""; print $0 }' |
tr -d '\"' |
tr -d ' '
)"
## copy package.json over
curl $auth_param -sL "${url}/package.json" -o "${cwd}/deps/${name}/package.json"
## make `deps/' directory if possible
mkdir -p "${cwd}/deps/${name}"
## make `deps/bin' directory if possible
mkdir -p "${cwd}/deps/bin"
# install package dependencies
(cd "${cwd}/deps/${name}" && bpkg getdeps)
## check if forced global
if [ ! -z $(echo -n $json | bpkg-json -b | grep '\["global"\]' | awk '{ print $2 }' | tr -d '"') ]; then
needs_global=1
fi
## construct scripts array
{
scripts=$(echo -n $json | bpkg-json -b | grep '\["scripts' | awk '{$1=""; print $0 }' | tr -d '"')
OLDIFS="${IFS}"
## comma to space
IFS=','
scripts=($(echo ${scripts[@]}))
IFS="${OLDIFS}"
## account for existing space
scripts=($(echo ${scripts[@]}))
}
## construct files array
{
files=$(echo -n $json | bpkg-json -b | grep '\["files' | awk '{$1=""; print $0 }' | tr -d '"')
OLDIFS="${IFS}"
## comma to space
IFS=','
files=($(echo ${files[@]}))
IFS="${OLDIFS}"
## account for existing space
files=($(echo ${files[@]}))
}
fi
## build global if needed
if (( 1 == $needs_global )); then
if (( 1 == $has_pkg_json )); then
## install bin if needed
build="$(echo -n ${json} | bpkg-json -b | grep '\["install"\]' | awk '{$1=""; print $0 }' | tr -d '\"')"
build="$(echo -n ${build} | sed -e 's/^ *//' -e 's/ *$//')"
fi
if [ -z "${build}" ]; then
warn "Missing build script"
warn "Trying \`make install'..."
build="make install"
fi
{(
## go to tmp dir
cd $( [ ! -z $TMPDIR ] && echo $TMPDIR || echo /tmp) &&
## prune existing
rm -rf ${name}-${version} &&
## shallow clone
info "Cloning $repo_url to $name-$version"
git clone $repo_url ${name}-${version} &&
(
## move into directory
cd ${name}-${version} &&
## build
info "Performing install: \`${build}'"
build_output=$(eval "${build}")
echo "$build_output"
) &&
## clean up
rm -rf ${name}-${version}
)}
fi
if [ "${#scripts[@]}" -gt "0" ]; then
## grab each script and place in deps directory
for (( i = 0; i < ${#scripts[@]} ; ++i )); do
(
local script="$(echo ${scripts[$i]} | xargs basename )"
info "fetch" "${url}/${script}"
info "write" "${cwd}/deps/${name}/${script}"
curl $auth_param -sL "${url}/${script}" -o "${cwd}/deps/${name}/${script}"
local scriptname="${script%.*}"
info "${scriptname} to PATH" "${cwd}/deps/bin/${scriptname}"
ln -si "${cwd}/deps/${name}/${script}" "${cwd}/deps/bin/${scriptname}"
chmod u+x "${cwd}/deps/bin/${scriptname}"
)
done
fi
if [ "${#files[@]}" -gt "0" ]; then
## grab each file
for (( i = 0; i < ${#files[@]} ; ++i )); do
(
local file="$(echo ${files[$i]})"
local filedir="$(dirname "${cwd}/deps/${name}/${file}")"
info "fetch" "${url}/${file}"
if [ ! -d "$filedir" ]; then
mkdir -p "$filedir"
fi
info "write" "${filedir}/${file}"
curl $auth_param -sL "${url}/${script}" -o "${filedir}/${file}"
)
done
fi
return 0
}
## Use as lib or perform install
if [[ ${BASH_SOURCE[0]} != $0 ]]; then
export -f bpkg_install
elif validate_parameters; then
bpkg_install "${@}"
exit $?
else
#param validation failed
exit $?
fi