]> git.donarmstrong.com Git - neurodebian.git/blob - tools/nd-aptenable
NF: initial sketch for a script to enable NeuroDebian repo on any Debian/Ubuntu system
[neurodebian.git] / tools / nd-aptenable
1 #!/bin/bash
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:
4
5 # play safe
6 set -e
7 set -u
8
9 ############
10 # Defaults #
11 ############
12
13 nd_aptenable_version=0.1
14
15 nd_key_id=0x2649A5A9
16
17 # To be set by cmdline args
18 ae_release=
19 ae_components=software,data
20 ae_flavor=
21 ae_mirror_main=http://neuro.debian.net/debian
22 ae_mirror=
23 ae_suffix=
24 ae_verbose=1
25 ae_overwrite=
26 ae_sources=
27 ae_dry_run=
28
29 ae_sudo=
30
31 # TODOs:
32 # - distribute/enable key
33 # - apt priority! (so we could avoid automagic upgrades etc)
34 # - multiarch setups
35
36
37 # TODO -- consider fetching the most recent version from online
38 # concerns -- without any validation might be subject to injection through man-in-the-middle etc
39 nd_configfile=/etc/neurodebian/neurodebian.cfg # TODO - comes from neurodebian-devel pkg...
40 # TODO: Or should it be parsed out from the NeuroDebian website itself?
41 #  may be we could provide that file from the neurodebian website...
42
43 print_verbose()
44 {
45     level=$1; shift
46         if [ "$ae_verbose" -ge $level ]; then
47         echo -e "I: $*"
48     fi
49 }
50
51 error()
52 {
53     code=$1; shift
54         echo -e "E: $*" >&2
55     exit $code
56 }
57
58 print_version()
59 {
60 cat << EOT
61 nd-aptenable $nd_aptenable_version
62
63 Copyright (C) 2014 Yaroslav Halchenko <debian@onerussian.com>
64
65 Licensed under GNU Public License version 3 or later.
66 This is free software; see the source for copying conditions.  There is NO
67 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
68
69 Written by Yaroslav Halchenko for the NeuroDebian project.
70
71 EOT
72 }
73
74 eval_dry()
75 {
76     if [ -z "$ae_dry_run" ]; then
77         eval "$ae_sudo $@"
78     else
79         echo "DRY: $@"
80     fi
81 }
82
83 print_help()
84 {
85 cat << EOT
86
87 Usage:  nd-aptenable [options]
88
89 Enables NeuroDebian repository for the current Debian or Ubuntu release.
90
91 Options:
92
93   -r, --release=RELEASE
94     Name of the Debian/Ubuntu release to be used.  If not specified,
95     it is deduced from the  apt-cache policy  output, by taking repository
96     of Debian or Ubuntu origin with highest priority.
97
98   -f, --flavor=full|libre
99     Which flavor of the repository should be enabled:
100      libre -- Only  main  component, containing only DFSG-compliant content.
101      full -- Includes main, contrib, and non-free.
102     If not specified -- deduced from the output of apt-cache policy
103
104   -c, --components=c1,c2,c3
105     Comma separated list of components to enable among:
106      software -- primary software repository
107      data -- data packages
108      devel -- "overlay" of development versions (like Debian "experimental").
109               Not sufficient on its own and available only from the main site
110     If not specified -- "software,data"
111
112   -m, --mirror=NAME|URL
113     Which mirror to use.  Could be a mirror code-name (as specified in
114     /etc/neurodebian/neurodebian.cfg), or a URL (TODO).
115
116   --overwrite,
117     If apt file already present, it would not be overriden (by default).
118     Use this option to overwrite.
119
120   --suffix=SUFFIX
121     Which suffix to add to the apt file, in case you are trying to enable
122     multiple repositories
123
124   --sources, --no-sources
125     Either to enable deb-src lines.  If not specified -- deduced based on ??? TODO
126
127   -n, --dry-run
128     Do not perform any changes -- generated configurations and commands will
129     simply be printed to stdout
130
131   -v, --verbose
132     Enable additional progress messages.  Could be used multiple times
133
134   -q, --quiet
135     Make operation quiet -- only error messages would be output
136
137   -h, --help
138     Print short description, usage summary and option list.
139
140   --version
141     Print version information and exit.
142
143 Exit status:
144
145   non-0 exit status in case of error.  Error exit code would depend
146   on which command has failed
147
148 Examples:
149
150   - Enable software and data components from the optimal (according to
151     netselect) mirror.  Some information about progress will be printed
152
153     nd-aptenable
154
155   - Quietly enable -devel repository for the current release, and place apt
156     configuration into /etc/apt/sources.list.d/neurodebian.sources-devel.list
157
158     nd-aptenable -q --suffix=-devel -c devel
159
160   - Force sid distribution, all the components, from the Japan mirror:
161
162     nd-aptenable -q --suffix=-de-sid-full -c software,data,devel -m jp
163
164 EOT
165 }
166
167 get_mirrors() {
168     # Determine available mirrors by fetching our .cfg file
169     /etc/neurodebian/neurodebian.cfg
170 }
171
172 print_mirrors() {
173     echo "TODO"
174     exit 1
175 }
176
177 get_apt_policy() {
178     # Get apt-cache policy output in a single list for matching suites
179     # (could be a separated with \| or , for multiple choices, e.g.
180     #
181     # get_apt_policy Debian,Ubuntu
182     # or
183     # get_apt_policy NeuroDebian
184     suites="$1"
185     apt-cache policy | grep -B1 -e "o=\(${suites//,/\\|}\)" | tr '\n' ' ' | sed -e 's, -- ,\n,g' | grep -v -e '-\(updates\|security\)' | sort -nr
186 }
187
188 include_component() {
189     echo "$ae_components" | tr ',' '\n' | grep -q "^$1\$"
190 }
191
192
193 #
194 # Commandline options handling
195 #
196
197 # Parse commandline options (taken from the getopt examples from the Debian util-linux package)
198 # Note that we use `"$@"' to let each command-line parameter expand to a
199 # separate word. The quotes around `$@' are essential!
200 # We need CLOPTS as the `eval set --' would nuke the return value of getopt.
201 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,dry-run,print-mirrors -n 'nd-aptenable' -- "$@"`
202
203 if [ $? != 0 ] ; then
204   error 2 "Problem with parsing cmdline.  Terminating..."
205 fi
206
207 # Note the quotes around `$CLOPTS': they are essential!
208 eval set -- "$CLOPTS"
209
210 while true ; do
211   case "$1" in
212           -r|--release) shift; ae_release="$1"; shift;;
213           -f|--flavor) shift;  ae_flavor="$1"; shift;;
214           -c|--components) shift; ae_components="$1"; shift;;
215       # TODO
216       -m|--mirror) shift;  ae_mirror="$1"; shift;;
217       # TODO
218          --print-mirrors)  print_mirrors; exit 0;;
219       -n|--dry-run)        ae_dry_run=1; shift;;
220          --suffix) shift;  ae_suffix="$1"; shift;;
221          --overwrite)      ae_overwrite="$1"; shift;;
222          --sources)        ae_sources=1; shift;;
223          --no-sources)     ae_sources=0; shift;;
224           -q|--quiet)          ae_verbose=0; shift;;
225           -v|--verbose)        ae_verbose=$(($ae_verbose+1)); shift;;
226           -h|--help) print_help; exit 0;;
227           --version) print_version; exit 0;;
228           --) shift ; break ;;
229           *) error 1 "Internal error! ($1)";;
230   esac
231 done
232
233
234 if [ $# -gt 0 ] ; then
235     print_help >&2
236     exit 2
237 fi
238
239
240 #
241 # Basic system/environment knowledge
242 #
243
244 ae_output_file=/etc/apt/sources.list.d/neurodebian.sources${ae_suffix}.list
245
246 if [ `whoami` != "root" ]; then
247     print_verbose 1 "This script requires root access.  Since current user is not root, sudo will be used"
248     ae_sudo=sudo
249 fi
250
251 apt_policy=$(get_apt_policy "Debian,Ubuntu" )
252
253 if [ -z "$ae_release" ]; then
254     ae_release=$(echo "$apt_policy" | head -1 | sed -e 's/.*,n=\([^,]*\),.*/\1/g')
255 fi
256
257 if [ -z "$ae_flavor" ]; then
258     ae_flavor=$(echo "$apt_policy" | grep -e ",n=$ae_release," | grep -qe 'c=\(non-free\|restricted\)' && echo "full" || echo "libre")
259 fi
260
261 #
262 # Determine which mirror to use
263 #
264
265 # TODO -- determine mirror URL
266 # Not necessary for -devel available only from the main site
267 if include_component software || include_component data; then
268     # for now just use default
269     if [ -z "$ae_mirror" ]; then # none specified
270         ae_mirror_url=$ae_mirror_main
271     else
272         if [ ! "$ae_mirror" ~= ".*://.*" ]; then
273             # TODO -- determine from the abbreviation
274         fi
275     fi
276 fi
277
278
279 #
280 # Prepare APT file
281 #
282
283 case $ae_flavor in
284  full)  apt_flavor="contrib non-free";;
285  libre) apt_flavor="";;
286  *) error 5 "Unknown value of flavor $apt_flavor.  Must be full or libre"
287 esac
288
289 if [ -z "$ae_sources" ] || [ $ae_sources -eq 0 ]; then
290     sources_comment="#"
291 else
292     sources_comment=""
293 fi
294
295 apt_list=
296
297 if include_component software; then
298     apt_list+="
299 # NeuroDebian software repository
300 deb     $ae_mirror_url $ae_release main $apt_flavor
301 ${sources_comment}deb-src $ae_mirror_url $ae_release main $apt_flavor
302 "
303 fi
304
305 if include_component data; then
306     apt_list+="
307 # NeuroDebian data repository
308 deb     $ae_mirror_url data main $apt_flavor
309 ${sources_comment}deb-src $ae_mirror_url data main $apt_flavor
310 "
311 fi
312
313 if include_component devel; then
314     apt_list+="
315 # NeuroDebian -devel repository
316 deb     http://neuro.debian.net/debian-devel $ae_release main $apt_flavor
317 ${sources_comment}deb-src http://neuro.debian.net/debian-devel $ae_release main $apt_flavor
318 "
319 fi
320
321 if [ -e "$ae_output_file" ] && [ -z "$ae_overwrite" ]; then
322     # error 3
323     print_verbose 1 "File $ae_output_file already exists, containing:\n\n`cat \"$ae_output_file\"`\n\nI: Use --overwrite option to regenerate with:\n\n$apt_list"
324 else
325     print_verbose 1 "Generating $ae_output_file"
326     if [ -z "$ae_dry_run" ]; then
327         echo "$apt_list" >| "$ae_output_file"
328     else
329         echo "DRY:"
330         echo "$apt_list"
331     fi
332 fi
333
334
335 #
336 # Assure present archive GPG key for APT system
337 #
338
339 # Figure out if key needs to be imported (if ran within package,
340 # should already be there due to neurodebian-keyring package)
341 if LANG=C eval $ae_sudo apt-key export $nd_key_id 2>&1 1>/dev/null | grep -qe "nothing exported"; then
342     print_verbose 1 "Fetching the key from the server"
343     eval_dry apt-key adv --recv-keys --keyserver pgp.mit.edu $nd_key_id
344 fi
345
346 #
347 # Finalizing (apt-get update etc)
348 #
349
350 print_verbose 1 "Updating APT listings, might take a few minutes"
351 if [ -z "$ae_dry_run" ]; then
352     apt_logfile=$(mktemp)
353     $ae_sudo apt-get update 1>"$apt_logfile" 2>&1 \
354         && rm -f "$apt_logfile" \
355         || {
356              cat "$apt_logfile"
357              error 5 "E: Update failed with exit code $? (above output logged into $apt_logfile)."
358              }
359 else
360     eval_dry apt-get update
361 fi
362
363 if [ "$ae_verbose" -ge 2 ]; then
364     print_verbose 2 "Currently enabled NeuroDebian suites/mirrors:"
365     get_apt_policy NeuroDebian
366 fi