]> vilimpoc.org git repositories - dotfiles/blame - setup-linux.sh
dotfiles: Linux dev-box provisioning script
[dotfiles] / setup-linux.sh
CommitLineData
6f6caf69
MV
1#!/bin/bash
2#
3# setup-linux.sh -- install everything needed to build rsync on Ubuntu.
4#
5# Tested on Ubuntu 22.04.5 LTS and 26.04 LTS. Covers both build systems:
6# the autoconf one (./configure && make) and the CMake one (CMakeLists.txt),
7# plus the optional feature libraries and the manpage generator.
8#
9# Usage:
10# ./setup-linux.sh # install required + optional
11# ./setup-linux.sh --minimal # required only (no ACLs/xattrs/zstd/...)
12# ./setup-linux.sh --dry-run # show what would be installed
13#
14# Safe to re-run: apt skips anything already present.
15
16set -uo pipefail
17
18MINIMAL=0
19DRY_RUN=0
20
21for arg in "$@"; do
22 case "$arg" in
23 --minimal) MINIMAL=1 ;;
24 --dry-run) DRY_RUN=1 ;;
25 -h|--help)
26 sed -n '2,17p' "$0" | sed 's/^# \{0,1\}//'
27 exit 0 ;;
28 *)
29 echo "setup-linux.sh: unknown option '$arg' (try --help)" >&2
30 exit 2 ;;
31 esac
32done
33
34# ---------------------------------------------------------------- helpers
35
36red() { printf '\033[31m%s\033[0m\n' "$*"; }
37green() { printf '\033[32m%s\033[0m\n' "$*"; }
38bold() { printf '\033[1m%s\033[0m\n' "$*"; }
39
40die() { red "ERROR: $*"; exit 1; }
41
42# ------------------------------------------------------- sanity checks
43
44command -v apt-get >/dev/null 2>&1 \
45 || die "no apt-get found -- this script is for Debian/Ubuntu systems."
46
47DISTRO="unknown"
48RELEASE="unknown"
49if [ -r /etc/os-release ]; then
50 # shellcheck disable=SC1091 # runtime file, not available to the linter
51 . /etc/os-release
52 DISTRO="${ID:-unknown}"
53 RELEASE="${VERSION_ID:-unknown}"
54fi
55
56bold "rsync build dependencies"
57echo " distro ......... ${PRETTY_NAME:-$DISTRO $RELEASE}"
58echo " architecture ... $(uname -m)"
59
60case "$DISTRO" in
61ubuntu|debian|linuxmint|pop) ;;
62*) echo
63 red "Warning: this script targets Ubuntu/Debian; '$DISTRO' is untested."
64 echo "Continuing anyway -- package names may differ."
65 ;;
66esac
67
68# apt needs root. Re-exec under sudo rather than sprinkling it around, so
69# that a single password prompt covers the whole run.
70if [ "$(id -u)" -ne 0 ] && [ "$DRY_RUN" -eq 0 ]; then
71 command -v sudo >/dev/null 2>&1 \
72 || die "not running as root and sudo is not installed."
73 echo
74 echo "Re-running under sudo..."
75 # Plain sudo, not "sudo -E": some sudoers configs refuse to preserve the
76 # environment, and the exports below happen in the root instance anyway.
77 exec sudo "$0" "$@"
78fi
79
80export DEBIAN_FRONTEND=noninteractive
81export NEEDRESTART_MODE=a # don't prompt about restarting services
82
83# ------------------------------------------------------------- packages
84
85# Needed to build rsync at all.
86REQUIRED=(
87 build-essential # gcc, g++, make, libc headers
88 gawk # rsync needs a modern awk for its code generators
89 autoconf # ./configure is generated from configure.ac
90 automake
91 python3 # manpage + header generators, and the test suite
92 cmake # the CMake build
93 ninja-build # ...and its default generator
94 git # version stamping (git-version.h)
95 pkg-config
96)
97
98# Optional: each one switches on an rsync feature. Missing ones only mean
99# a smaller feature set, never a failed build.
100OPTIONAL=(
101 acl libacl1-dev # --acls (helper tools also used by the tests)
102 attr libattr1-dev # --xattrs (likewise)
103 libxxhash-dev # xxhash checksums (becomes the default)
104 libzstd-dev # zstd compression (becomes the default)
105 liblz4-dev # lz4 compression
106 libssl-dev # OpenSSL MD4/MD5
107 zlib1g-dev # for cmake -DRSYNC_EXTERNAL_ZLIB=ON
108 libpopt-dev # for ./configure --with-included-popt=no
109)
110
111# Development tooling: not needed to build rsync, but useful when working on
112# its shell scripts -- including this one, which shellcheck keeps honest.
113DEVTOOLS=(
114 shellcheck
115)
116OPTIONAL+=("${DEVTOOLS[@]}")
117
118# The manpages need one of two python3 markdown libraries; upstream prefers
119# cmarkgfm. Pick whichever this release actually offers.
120MARKDOWN_PKG=""
121for p in python3-cmarkgfm python3-commonmark; do
122 cand=$(apt-cache policy "$p" 2>/dev/null | awk '/Candidate:/{print $2}')
123 if [ -n "$cand" ] && [ "$cand" != "(none)" ]; then
124 MARKDOWN_PKG="$p"
125 break
126 fi
127done
128if [ -n "$MARKDOWN_PKG" ]; then
129 OPTIONAL+=("$MARKDOWN_PKG")
130fi
131
132if [ "$MINIMAL" -eq 1 ]; then
133 OPTIONAL=()
134fi
135
136if [ "$DRY_RUN" -eq 1 ]; then
137 echo
138 bold "Would install (required):"
139 printf ' %s\n' "${REQUIRED[@]}"
140 if [ ${#OPTIONAL[@]} -gt 0 ]; then
141 bold "Would install (optional):"
142 printf ' %s\n' "${OPTIONAL[@]}"
143 fi
144 exit 0
145fi
146
147# ------------------------------------------------------------- install
148
149echo
150bold "Updating package lists..."
151if ! apt-get update -qq; then
152 red "apt-get update failed -- continuing with the cached lists."
153fi
154
155echo
156bold "Installing required packages..."
157if ! apt-get install -y "${REQUIRED[@]}"; then
158 # Fall back to one-at-a-time so the failing package is obvious.
159 red "Bulk install failed; retrying individually to find the culprit..."
160 FAILED=()
161 for p in "${REQUIRED[@]}"; do
162 apt-get install -y "$p" || FAILED+=("$p")
163 done
164 [ ${#FAILED[@]} -eq 0 ] || die "could not install: ${FAILED[*]}"
165fi
166
167OPT_FAILED=()
168if [ ${#OPTIONAL[@]} -gt 0 ]; then
169 echo
170 bold "Installing optional packages..."
171 if ! apt-get install -y "${OPTIONAL[@]}"; then
172 red "Bulk install failed; retrying individually..."
173 for p in "${OPTIONAL[@]}"; do
174 apt-get install -y "$p" || OPT_FAILED+=("$p")
175 done
176 fi
177fi
178
179# --------------------------------------------------------------- verify
180
181echo
182bold "Verifying the toolchain..."
183
184MISSING=()
185check_cmd() {
186 if command -v "$1" >/dev/null 2>&1; then
187 printf ' %-16s %s\n' "$1" "$(command -v "$1")"
188 else
189 printf ' %-16s %s\n' "$1" "MISSING"
190 MISSING+=("$1")
191 fi
192}
193
194for c in gcc g++ make gawk autoconf automake cmake ninja python3 git; do
195 check_cmd "$c"
196done
197
198# Not required to build, so report it without failing the run.
199if command -v shellcheck >/dev/null 2>&1; then
200 printf ' %-16s %s\n' "shellcheck" "$(command -v shellcheck)"
201else
202 printf ' %-16s %s\n' "shellcheck" "not installed (optional)"
203fi
204
205echo
206bold "Verifying optional libraries..."
207check_header() {
208 # $1 = human name, $2 = header path
209 if [ -e "/usr/include/$2" ] || \
210 find /usr/include -maxdepth 3 -name "$(basename "$2")" -print -quit \
211 2>/dev/null | grep -q .; then
212 printf ' %-16s yes\n' "$1"
213 else
214 printf ' %-16s no\n' "$1"
215 fi
216}
217check_header acl sys/acl.h
218check_header xattr sys/xattr.h
219check_header xxhash xxhash.h
220check_header zstd zstd.h
221check_header lz4 lz4.h
222check_header openssl openssl/md5.h
223check_header zlib zlib.h
224
225echo
226bold "Verifying the manpage generator..."
227MD_OK=0
228for m in cmarkgfm commonmark; do
229 if python3 -c "import $m" >/dev/null 2>&1; then
230 echo " python3 module '$m' importable"
231 MD_OK=1
232 break
233 fi
234done
235if [ "$MD_OK" -eq 0 ]; then
236 if [ "$MINIMAL" -eq 1 ]; then
237 echo " skipped (--minimal); build with ./configure --disable-md2man"
238 else
239 red " neither cmarkgfm nor commonmark is importable."
240 echo " Install one with: python3 -mpip install --user commonmark"
241 echo " ...or build with: ./configure --disable-md2man"
242 fi
243fi
244
245# ---------------------------------------------------------------- done
246
247echo
248if [ ${#MISSING[@]} -ne 0 ]; then
249 red "Missing required tools: ${MISSING[*]}"
250 exit 1
251fi
252
253if [ ${#OPT_FAILED[@]} -ne 0 ]; then
254 red "Optional packages that failed to install: ${OPT_FAILED[*]}"
255 echo "The build will still work, with those features disabled."
256fi
257
258green "All required build dependencies are installed."
259cat <<'EOF'
260
261Build rsync with either build system:
262
263 autoconf: ./configure && make
264 CMake: cmake -B build -G Ninja && cmake --build build
265
266Run the test suite (needs the autoconf build's helper programs):
267
268 make check
269EOF