tools/setup.sh

227 lines
5.6 KiB
Bash
Executable file

#!/usr/bin/env bash
# Run this script to install or update your dmd toolchain from
# github.
#
# First run, create a working directory, e.g. /path/to/d/. Then run
# this script from that directory (the location of the script itself
# doesn't matter). It will create the following subdirectories:
# /path/to/d/dmd, /path/to/d/phobos, /path/to/d/dlang.org,
# /path/to/d/tools, and /path/to/d/installer. Then it will fetch all
# corresponding projects from github and build them fresh.
#
# On an ongoing basis, to update your toolchain from github go again
# to the same directory (in our example /path/to/d) and run the script
# again. The script will detect that directories exist and will do an
# update.
#
set -ueo pipefail
declare -a projects
projects=(dmd phobos dlang.org tools installer dub)
# Working directory
wd=$(pwd)
# github username
githubUser="dlang"
# Configuration
makecmd="make"
parallel=8
model=64
build="release"
githubUri="https://github.com/"
tag=""
# List of projects to install vs. update. Their disjoint union is
# $projects.
declare -a toInstall toUpdate
toInstall=()
toUpdate=()
# Mess to go here
tempdir=$(mktemp -d /tmp/dmd-update.XXX)
function cleanup() {
rm -rf "$tempdir";
}
trap cleanup EXIT
function help() {
echo "./setup.sh
Clones and builds dmd, phobos, dlang.org, tools, installer and dub.
Additional usage
install replace current dmd binary with the freshly dmd
Options
--user=USER set a custom GitHub user name (requires the repos to be forked)
--tag=TAG select a specific tag to clone" >&2
}
#
# Take care of the command line arguments
#
function handleCmdLine() {
for arg in "$@"; do
case "$arg" in
--tag=*)
tag="${arg//[-a-zA-Z0-9]*=/}"
;;
--user=*)
githubUser="${arg//[-a-zA-Z0-9]*=/}"
;;
install)
install="yes"
;;
*)
echo "Error: $arg not recognized." >&2
echo >&2
help
exit 1
;;
esac
done
if [ -n "${tag+x}" ] ; then
wd+="/$tag"
mkdir -p "$wd"
fi
}
#
# Confirm correct choices
#
function confirmChoices() {
function joinWithWorkingDir() {
for i in "$@"; do
echo "$wd/$i"
done
}
for project in "${projects[@]}" ; do
if [ -d "$wd/$project" ] ; then
toUpdate+=("$project")
else
toInstall+=("$project")
fi
done
if [[ ${#toInstall[@]} -gt 0 ]]; then
echo "*** The following projects will be INSTALLED:"
joinWithWorkingDir "${toInstall[@]}"
fi
if [[ ${#toUpdate[@]} -gt 0 ]]; then
echo "*** The following projects will be UPDATED:"
joinWithWorkingDir "${toUpdate[@]}"
fi
echo "Is this what you want? [y|n]"
local yn
while true; do
read -r yn
case "$yn" in
[Yy]* ) break;;
[Nn]* ) exit;;
* ) echo "Please answer y or n.";;
esac
done
}
#
# Install from scratch
#
function installAnew() {
local projects
projects=("$@")
for project in "${projects[@]}" ; do
(
git clone "${githubUri}${githubUser}/$project.git" "$wd/$project"
if [ "$githubUser" != "dlang" ] ; then
git -C "$wd/$project" remote add upstream "${githubUri}dlang/$project.git"
fi
touch "$tempdir/$project"
) &
done
wait
for project in "${projects[@]}" ; do
if [ ! -f "$tempdir/$project" ]; then
echo "Getting $project failed." >&2
exit 1
fi
if [ -n "${tag}" ] ; then
if [ "$project" == "dmd" ] || [ "$project" == "phobos" ] || \
[ "$project" == "dlang.org" ] || [ "$project" == "tools" ] ; then
git -C "$wd/$project" checkout "v$tag"
fi
fi
done
}
#
# Freshen existing stuff
#
function update() {
echo "Updating projects in $wd..."
function update_project() {
local project=$1
local gitproject="${githubUri}dlang/$project.git"
local git=("git" "-C" "$wd/$project")
if ! ( \
"${git[@]}" checkout master && \
"${git[@]}" pull --ff-only --tags "$gitproject" master ) 2> "$tempdir/$project.log"
then
echo "Failure updating $wd/$project." >> "$tempdir/errors"
exit 1
fi
}
for project in "${toUpdate[@]}" ; do
update_project "$project" &
done
wait
if [ -f "$tempdir/errors" ]; then
cat "$tempdir"/*.log >&2
exit 1
fi
}
function makeWorld() {
local BOOTSTRAP=""
command -v dmd >/dev/null || BOOTSTRAP="AUTO_BOOTSTRAP=1"
for repo in dmd phobos ; do
# Pass `AUTO_BOOTSTRAP` because of https://issues.dlang.org/show_bug.cgi?id=20727
"$makecmd" -C "$wd/$repo" -f posix.mak clean $BOOTSTRAP
"$makecmd" -C "$wd/$repo" -f posix.mak "-j${parallel}" MODEL="$model" BUILD="$build" $BOOTSTRAP
done
# Update the running dmd version (only required once)
if [[ -n "${install+x}" ]]; then
local old dmdBinary
old=$(command -v dmd)
dmdBinary=$(ls -1 $wd/dmd/generated/*/$build/$model/dmd)
if [ -f "$old" ]; then
echo "Linking '$dmdBinary' to $old"
local sudo=""
if [ ! -w "$old" ] ; then
sudo="sudo"
fi
ln -s "$tempdir/dmd.symlink" "$old"
"$sudo" mv "$tempdir/dmd.symlink" "$old"
fi
fi
}
# main
handleCmdLine "$@"
confirmChoices
if [ ${#toInstall[@]} -gt 0 ] ; then
installAnew "${toInstall[@]}"
fi
if [ ${#toUpdate[@]} -gt 0 ] ; then
update "${toUpdate[@]}"
fi
makeWorld