2 #emacs: -*- mode: shell-script; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-
3 #ex: set sts=4 ts=4 sw=4 et:
5 # Depends: apt (assumed to be present), python, wget
6 # Recommends: netselect
16 nd_aptenable_version=0.1
18 nd_key_id=0xA5D32F012649A5A9
19 nd_config_url=https://raw.githubusercontent.com/neurodebian/neurodebian/master/neurodebian.cfg
20 nd_config_file=/etc/neurodebian/neurodebian.cfg
21 nd_mirror_origin=http://neuro.debian.net/debian
22 nd_mirror_default=$nd_mirror_origin # or may be AWS?
24 # To be set by cmdline args or via env variables with prefix NEURODEBIAN_
25 ae_release=${NEURODEBIAN_RELEASE:-}
26 ae_components=${NEURODEBIAN_COMPONENTS:-software,data}
27 ae_flavor=${NEURODEBIAN_FLAVOR:-}
28 ae_mirror=${NEURODEBIAN_MIRROR:-best}
29 ae_suffix=${NEURODEBIAN_SUFFIX:-}
30 ae_verbose=${NEURODEBIAN_VERBOSE:-1}
31 ae_overwrite=${NEURODEBIAN_OVERWRITE:-}
32 ae_sources=${NEURODEBIAN_SOURCES:-}
33 ae_install=${NEURODEBIAN_INSTALL:-}
34 ae_update=${NEURODEBIAN_UPDATE:-1}
35 ae_dry_run=${NEURODEBIAN_DRY_RUN:-}
36 ae_defun_only=${NEURODEBIAN_DEFUN_ONLY:-} # mode to source this file as a "library"
44 # - apt priority! (so we could avoid automagic upgrades etc)
47 if [ -z "${NEURODEBIAN_TEMPDIR:-}" ]; then
48 ae_tempdir=$(mktemp -d)
49 trap "rm -rf \"$ae_tempdir\"" TERM INT EXIT
51 # reuse the same directory/fetched configuration if was specified
52 ae_tempdir="${NEURODEBIAN_TEMPDIR:-}"
56 nd_config_file_fresh="$ae_tempdir/neurodebian.cfg"
61 if [ "$ae_verbose" -ge $level ]; then
62 # use stderr for printing within functions stdout of which might be used
64 i=1; while [ $i -lt $level ]; do echo -ne " ">&2; i=$(($i+1)); done
79 nd-configurerepo $nd_aptenable_version
81 Copyright (C) 2014 Yaroslav Halchenko <debian@onerussian.com>
83 Licensed under GNU Public License version 3 or later.
84 This is free software; see the source for copying conditions. There is NO
85 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
87 Written by Yaroslav Halchenko for the NeuroDebian project.
94 if [ -z "$ae_dry_run" ]; then
95 if eval "$ae_sudo $@" 1>|"$ae_tempdir/eval.log" 2>&1; then
96 rm "$ae_tempdir/eval.log"
98 error $? "Command $@ failed with exit code $?. Output was: `cat $ae_tempdir/eval.log`"
109 Usage: nd-configurerepo [options]
111 Enables NeuroDebian repository for the current Debian or Ubuntu release.
115 -r, --release=RELEASE
116 Name of the Debian/Ubuntu release to be used. If not specified,
117 it is deduced from the 'apt-cache policy' output, by taking repository
118 of Debian or Ubuntu origin with highest priority.
121 Print a list of releases present in NeuroDebian repository.
124 Print the release deduced from the output of apt-cache policy.
126 -f, --flavor=full|libre
127 Which flavor of the repository should be enabled:
129 libre Only 'main' component, containing only DFSG-compliant content.
130 full Includes 'main', 'contrib', and 'non-free'.
132 If not specified -- deduced from the output of apt-cache policy.
135 Print the flavor deduced from the output of apt-cache policy.
137 -c, --components=c1,c2,c3
138 Comma separated list of components to enable among:
140 software primary software repository
142 devel "overlay" of development versions (like Debians' "experimental").
143 Not sufficient on its own and available only from the main site
145 If not specified -- "software,data"
147 -m, --mirror=NAME|URL
148 Which mirror to use. Could be a mirror code-name (as specified in
149 /etc/neurodebian/neurodebian.cfg), or a URL.
152 Return a list (with abbreviation) of known NeuroDebian mirrors.
155 If apt file already present, it would not be overriden (by default).
156 Use this option to overwrite.
159 Which suffix to add to the apt file, in case you are trying to enable
160 multiple repositories
162 --sources, --no-sources
163 Either to enable deb-src lines. If none specified -- would be enabled if
164 sources for a core package (apt) are available.
167 Do not perform any changes -- generated configurations and commands will
168 simply be printed to stdout
171 If found absent, all necessary tools (wget, netselect) if available will
175 Enable additional progress messages. Could be used multiple times
178 Make operation quiet -- only error messages would be output
181 Print short description, usage summary and option list.
184 Print version information and exit.
188 non-0 exit status in case of error.
189 Error exit code would depend on which command has failed.
193 Enable software and data components from the optimal (according to
194 netselect) mirror. Some information about progress will be printed
196 nd-configurerepo -q --suffix=-devel -c devel
197 Quietly enable -devel repository for the current release, and place apt
198 configuration into /etc/apt/sources.list.d/neurodebian.sources-devel.list
200 nd-configurerepo -q --suffix=-de-sid-full -c software,data,devel -m jp
201 Force sid distribution, all the components, from the Japan mirror
205 get_neurodebian_cfg()
207 if [ -s "$nd_config_file_fresh" ]; then
208 print_verbose 3 "Config file $nd_config_file_fresh exists -- not fetching"
209 echo "$nd_config_file_fresh"
212 # First we try to fetch the most recent version from the github
213 print_verbose 3 "Fetching config file from the github repository"
214 assure_command_from_package wget wget 1
215 wget --no-check-certificate -c -q -O$nd_config_file_fresh \
217 && { echo "$nd_config_file_fresh"; } \
218 || { [ -e "$nd_config_file" ] \
219 && echo "$nd_config_file" \
220 || error 10 "Neither could fetch $nd_config_url, nor found $nd_config_file"; }
227 print_verbose 3 "Querying config $config_file section $section"
228 assure_command_from_package python python-minimal 1
229 python -c "from ConfigParser import SafeConfigParser as SP; cfg = SP(); cfg.read('$config_file'); print('\n'.join([' '.join(x) for x in cfg.items('$section')]))"
234 nd_config=`get_neurodebian_cfg`
235 # $exe_dir/nd_querycfg -F" " --config-file="$nd_config" "mirrors" \
237 query_cfg_section "$nd_config" "mirrors" \
238 | while read mirror_name mirror_url; do
239 # verify that url is just a url
240 if echo "$mirror_url" | grep -v -e '^[a-z0-9:+]*://[-+_%.a-z0-9/]*$'; then
241 print_verbose 1 "Mirror $mirror_name has 'illegit' URL: $mirror_url. Skipping"
243 [ -z "$n" ] || echo -ne "${ND_IFS:-\n}"; n+=1
244 echo -n "$mirror_name $mirror_url"
250 nd_config=`get_neurodebian_cfg`
252 query_cfg_section "$nd_config" "release files" \
253 | while read release_name release_url; do
254 # verify that url is just a url
255 if [ "$release_name" = "data" ]; then
259 [ -z "$n" ] || echo -ne "${ND_IFS:-\n}"; n+=1
260 echo -n "$release_name"
264 get_package_version()
266 pkg_version=$(apt-cache policy "$1" | awk '/^ *Installed:/{print $2;}')
267 [ "$pkg_version" != '(none)' ] || pkg_version=''
272 # select "closest" mirror according to netselect.
273 print_verbose 2 "Selecting the 'best' mirror using netselect"
274 assure_command_from_package netselect
275 if ! which netselect >&/dev/null; then
276 print_verbose 1 "netselect (apt-get install netselect) needed to select the 'best' mirror was not found"
277 print_verbose 1 "Selecting the default repository: $nd_mirror_default"
278 echo $nd_mirror_default
280 # squeeze version doesn't have -D yet to force output of the URL not IP, but for our mirrors ATM it shouldn't matter
281 netselect_opts="-s 1"
282 netselect_version="$(get_package_version netselect)"
283 if dpkg --compare-versions "$netselect_version" ge 0.3.ds1-17; then
284 netselect_opts+=" -D"
286 if dpkg --compare-versions "$netselect_version" ge 0.3.ds1-15; then
287 netselect_opts+=" -I"
289 best_mirror=$(get_mirrors | awk '{print $2;}' | eval $ae_sudo xargs netselect $netselect_opts | awk '{print $2;}')
290 if [ -z "$best_mirror" ]; then
291 print_verbose 1 "Failed to select mirror using netselect. Selecting default one ($nd_mirror_default)"
292 echo "$nd_mirror_default"
294 print_verbose 2 "Best mirror: $best_mirror"
302 # given mirror alias -- find its url
303 url=$(get_mirrors | awk "/^$1 /{print \$2;}")
304 if [ -z "$url" ]; then
305 error 9 "Cannot resolve mirror $1 to the URL"
312 # Get apt-cache policy output in a single list for matching suites
313 # (could be a separated with \| or , for multiple choices, e.g.
315 # get_apt_policy Debian,Ubuntu
317 # get_apt_policy NeuroDebian
319 $ae_sudo apt-cache policy | grep -B1 -e "o=\(${suites//,/\\|}\)" | tr '\n' ' ' | sed -e 's, -- ,\n,g' | grep -v -e '-\(updates\|security\)' | sort -nr
322 is_component_included()
324 echo "$ae_components" | tr ',' '\n' | grep -q "^$1\$"
329 apt-cache showsrc apt >&/dev/null && echo 1 || echo 0
332 assure_command_from_package()
338 which "$cmd" >&/dev/null && return 0
340 # if absent -- check availability of the package
341 apt_cache=$(LANG=C apt-cache policy "$pkg" 2>&1)
342 if [[ "$apt_cache" =~ Unable\ to\ locate\ package ]] || [[ "$apt_cache" =~ Candidate:\ (none) ]]; then
343 print_verbose 1 "Package $pkg providing command $cmd is N/A. Skipping"
346 if echo "$apt_cache" | grep -q '^\s*\*\*\*'; then
347 print_verbose 1 "WARNING -- command $cmd is N/A but package $pkg is claimed to be installed"
348 [ -z "$fail" ] && return 11 || error $fail "Command $cmd is required to proceed"
350 if [ "$ae_install" = "1" ]; then
351 print_verbose 1 "Installing $pkg package to get $cmd command"
352 eval_dry DEBIAN_FRONTEND=noninteractive apt-get install -y "$pkg"
355 print_verbose 1 "Command $cmd (from package $pkg) is N/A."
356 print_verbose 1 "Use with --install to get all necessary packages installed automatically"
357 [ -z "$fail" ] && return 12 || error $fail "Command $cmd is required to proceed"
361 # if it was requested -- return without doing anything
362 [ -z "$ae_defun_only" ] || return
365 # Commandline options handling
368 # Parse commandline options (taken from the getopt examples from the Debian util-linux package)
369 # Note that we use `"$@"' to let each command-line parameter expand to a
370 # separate word. The quotes around `$@' are essential!
371 # We need CLOPTS as the `eval set --' would nuke the return value of getopt.
372 CLOPTS=`getopt -o h,r:,m:,f:,c:,q,v,n --long help,version,quiet,verbose,mirror:,release:,flavor:,components:,suffix:,overwrite,sources,no-sources,install,dry-run,do-not-update,print-releases,print-release,print-mirrors,print-best-mirror,print-flavor -n 'nd-configurerepo' -- "$@"`
374 if [ $? != 0 ] ; then
375 error 2 "Problem with parsing cmdline. Terminating..."
378 # Note the quotes around `$CLOPTS': they are essential!
379 eval set -- "$CLOPTS"
381 if [ `whoami` != "root" ]; then
387 -r|--release) shift; ae_release="$1"; shift;;
388 -f|--flavor) shift; ae_flavor="$1"; shift;;
389 -c|--components) shift; ae_components="$1"; shift;;
390 -m|--mirror) shift; ae_mirror="$1"; shift;;
391 --print-mirrors) get_mirrors; exit 0;;
392 --print-best-mirror) netselect_mirror; exit 0;;
393 --print-releases) get_releases; exit 0;;
394 --print-release) do_print_release=1; shift;;
395 --print-flavor) do_print_flavor=1; shift;;
396 -n|--dry-run) ae_dry_run=1; shift;;
397 --suffix) shift; ae_suffix="$1"; shift;;
398 --overwrite) ae_overwrite="$1"; shift;;
399 --do-not-update) ae_update=""; shift;;
400 --sources) ae_sources=1; shift;;
401 --no-sources) ae_sources=0; shift;;
402 --install) ae_install=1; shift;;
403 -q|--quiet) ae_verbose=0; shift;;
404 -v|--verbose) ae_verbose=$(($ae_verbose+1)); shift;;
405 -h|--help) print_help; exit 0;;
406 --version) print_version; exit 0;;
408 *) error 1 "Internal error! ($1)";;
413 if [ $# -gt 0 ] ; then
419 [ -z "$ae_sudo" ] || print_verbose 1 "This script requires root access. Since current user is not root, sudo will be used"
422 # Basic system/environment knowledge
425 ae_output_file=/etc/apt/sources.list.d/neurodebian.sources${ae_suffix}.list
427 apt_policy=$(get_apt_policy "Debian,Ubuntu" )
429 if [ -z "$ae_release" ]; then
430 ae_release=$(echo "$apt_policy" | head -1 | sed -e 's/.*,n=\([^,]*\),.*/\1/g')
431 if [ ! -z "$do_print_release" ]; then
437 if [ -z "$ae_flavor" ]; then
438 ae_flavor=$(echo "$apt_policy" | grep -e ",n=$ae_release," | grep -qe 'c=\(non-free\|multiverse\)' && echo "full" || echo "libre")
439 if [ ! -z "$do_print_flavor" ]; then
446 # Determine which mirror to use
449 # knowing mirror is not necessary for -devel available only from the main site
450 if is_component_included software || is_component_included data; then
451 # for now just use default
452 if [ -z "$ae_mirror" ]; then # none specified
453 ae_mirror_url=$nd_mirror_origin
455 if ! [[ "$ae_mirror" =~ .*://.* ]]; then
457 best) ae_mirror_url=$(netselect_mirror);;
458 default) ae_mirror_url=$nd_mirror_default;;
459 origin) ae_mirror_url=$nd_mirror_origin;;
460 *) ae_mirror_url=$(get_mirror_url "$ae_mirror");;
463 ae_mirror_url="$ae_mirror" # it was some kind of a URL already
473 full) apt_flavor="contrib non-free";;
474 libre) apt_flavor="";;
475 *) error 5 "Unknown value of flavor $apt_flavor. Must be full or libre"
478 if [ -z "$ae_sources" ]; then
479 ae_sources=$(is_sources_enabled)
482 if [ $ae_sources -eq 0 ]; then
490 if is_component_included software; then
492 # NeuroDebian software repository
493 deb $ae_mirror_url $ae_release main $apt_flavor
494 ${sources_comment}deb-src $ae_mirror_url $ae_release main $apt_flavor
498 if is_component_included data; then
500 # NeuroDebian data repository
501 deb $ae_mirror_url data main $apt_flavor
502 ${sources_comment}deb-src $ae_mirror_url data main $apt_flavor
506 if is_component_included devel; then
508 # NeuroDebian -devel repository
509 deb http://neuro.debian.net/debian-devel $ae_release main $apt_flavor
510 ${sources_comment}deb-src http://neuro.debian.net/debian-devel $ae_release main $apt_flavor
514 if [ -e "$ae_output_file" ] && [ -z "$ae_overwrite" ]; then
515 if diff "$ae_output_file" <(echo "$apt_list") | grep -q .; then
517 print_verbose 1 "File $ae_output_file already exists, containing:\n`cat \"$ae_output_file\"`\n\nI: New configuration is different:\n$apt_list"
518 if get_apt_policy NeuroDebian >/dev/null; then
519 print_verbose 1 "NeuroDebian repositories are already available, thus skipping the rest."
520 print_verbose 1 "Rerun with --overwrite if you would like to reconfigure."
523 print_verbose 1 "NeuroDebian configuration is found but not yet available -- continuing with new configuration."
526 print_verbose 1 "New configuration is identical to existing and NeuroDebian repository is already enabled."
527 print_verbose 1 "Skiping the rest. Rerun with --overwrite if you would like to reconfigure."
531 print_verbose 1 "Generating $ae_output_file"
532 if [ -z "$ae_dry_run" ]; then
533 echo "$apt_list" | $ae_sudo bash -c "cat - >| '$ae_output_file'"
542 # Assure present archive GPG key for APT system
545 # Figure out if key needs to be imported (if ran within package,
546 # should already be there due to neurodebian-keyring package)
547 if LANG=C eval $ae_sudo apt-key export $nd_key_id 2>&1 1>/dev/null | grep -qe "nothing exported"; then
548 print_verbose 1 "Fetching the key from the server"
549 eval_dry apt-key adv --recv-keys --keyserver pgp.mit.edu $nd_key_id
554 # Finalizing (apt-get update etc)
557 if [ ! -z "$ae_update" ]; then
558 print_verbose 1 "Updating APT listings, might take a few minutes"
559 if [ -z "$ae_dry_run" ]; then
560 apt_logfile="$ae_tempdir/apt.log"
561 $ae_sudo apt-get update 1>"$apt_logfile" 2>&1 \
562 && rm -f "$apt_logfile" \
564 apt_log=$(cat "$apt_logfile")
566 if echo "$apt_log" | grep -q "Malformed line [0-9]* in source list $ae_output_file"; then
567 $ae_sudo mv "${ae_output_file}" "${ae_output_file}-failed.disabled"
568 error 6 "Update failed to possible errorneous APT listing file produced by this script. Generated $ae_output_file renamed to ${ae_output_file}-failed.disabled to not interfer"
570 error 5 "Update failed with exit code $? (above output logged into $apt_logfile)."
573 eval_dry apt-get update
576 print_verbose 1 "apt-get update was not run. Please run to take an effect of changes"
579 if [ "$ae_verbose" -ge 2 ]; then
580 print_verbose 2 "Currently enabled NeuroDebian suites/mirrors:"
581 get_apt_policy NeuroDebian