summaryrefslogtreecommitdiff
path: root/wrappers/dpkg-checkbuilddeps
blob: 1f729e061028343330267f06b21189602517532d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
#!/bin/bash
#
# Copyright (C) 2007 Lauri Leukkunen <lle@rahina.org>
#
# Redesigned/refactored by Lauri T. Aarnio;
#	Portion Copyright (c) 2008 Nokia Corporation.
#	All rights reserved.
#
# Licensed under GPL version 2
#
# -------------------
#
# dpkg-checkbuilddeps wrapper for SB2.
#
# Currently there are two algorithms for this: Old and new.
#
# The old one, implemented completely as a shell script,
# ignores many things that should be checked. The new one is 
# is written in perl, but the implementation is still
# incomplete. Currently things work so that this shell
# script digs out the needed variables and feeds them to
# the perl script (the old algorithm is off by default).
#
# Alternatively, the old and new algorithms can both be
# enable by setting environment variable SBOX_DOUBLECHECK_DEPS
# to any non-empty value. I haven't seen any cases where the
# old algorithm would be better that the new one, but I'm
# interested to hear if there are any...before this old
# stuff will be completely removed / Lauri T. Aarnio 2009-01-31.
#
# Here is description of the OLD algorithm:
# Idea behind operation is to first check target's package db,
# then check if missing packages are tools that could be used
# from the host (or sbox_tools_root, if that has been set)
#
# There might also be dependencies that SB2 itself solves;
# for example, gcc-* dependencies might be resolved by the
# cross compiler.
#
# Requirements:
# - Package db maps to *target* package db
# - can switch temporarily to tools mode, and then the
#   db maps to *tools* package db
#
# [N.B. The new algorithm solves this:
# FIXME: This implementation is still incomplete, as this does not
# check package versions while checking host/tools_root tools.
# Also, it would be a good idea to do a "visibility check" for host packages,
# too (see how sb2-check-pkg-mappings does it for target's pkg db)]

args="$*"
prog="$0"
progbase=`basename $0`

SBOX_REDIRECT_IGNORE=""

function error_not_inside_sb2()
{
	echo "SB2: $progbase: This wrapper can only be used from inside"
	echo "the scratchbox 2'ed environment"
	exit 1
}

if [ -z "$SBOX_SESSION_DIR" ]
then
	error_not_inside_sb2
fi

. $SBOX_SESSION_DIR/sb2-session.conf

# A generated, temporary package db which only contains packages that
# are usable thru the current mapping mode:
TARGET_DPKG_ADMINDIR_USABLE_PKGS=$sbox_temp_dpkg_admin_dir

cfgfile_host_accepted_pkgs=$sbox_dir/share/scratchbox2/modeconf/host-accepted-packages.$sbox_mapmode
cfgfile_host_ignored_pkgs=$sbox_dir/share/scratchbox2/modeconf/host-ignored-packages.$sbox_mapmode

# Execute a command in tools mode. forces /usr/bin/perl to tools,
# otherwise the shell which is running this script may try to take perl from
# the rootstrap - some, but not all, of the dpkg* tools are perl scripts.
# Return status is in $tools_mode_tool_stat when this returns.
function run_in_tools_mode()
{
	SBOX_REDIRECT_FORCE="/usr/bin/perl" SBOX_SESSION_MODE=tools \
		eval "$*"
	tools_mode_tool_stat=$?
}

# Check if a named package exists of the host.
# Returns result in three variables:
# - $installed_to_host is either "yes" or "no"
# - $check_result_msg and $check_result_msg2 return a more detailed
#   explanation of the result (strings).
function check_host_pkg()
{
	pkgname=$1

	installed_to_host="no"	# default
	check_result_msg="'$pkgname' not found."
	check_result_msg2=""

	# Check if it can be accepted from the host:
	g=`grep "^$pkgname\$" $cfgfile_host_accepted_pkgs`
	if [ -z "$g" ]
	then
		# No, the package has not been aproved to be used from the host.

		# first check if this requirement should be ignored completely:
		if [ -f $cfgfile_host_ignored_pkgs ]
		then
			# ignorelist exists
			g=`grep "^$pkgname\$" $cfgfile_host_ignored_pkgs`
			if [ -z "$g" ]
			then
				check_result_msg="'$pkgname' is missing (must be installed to the rootstrap)"
			else
				check_result_msg="'$pkgname' is missing, but this is ignored by configuration"
				installed_to_host="yes"
				return
			fi
		fi

		pkg_stat_tmp=`mktemp -p $SBOX_SESSION_DIR/tmp pkg-stat.XXXXXXXXXX`
		# next check again if the package exists on the target,
		# just to be able to give a better error message.
		if dpkg-query -s "$pkgname" >$pkg_stat_tmp 2>&1
		then
			if grep -q "ok installed" $pkg_stat_tmp
			then
				rm $pkg_stat_tmp
				check_result_msg="'$pkgname': OOPS. Needed from the the rootstrap (installed there),"
				check_result_msg2="   but unusable (not fully visible due to SB2 mapping rules)"
				return
			fi
		fi
		rm $pkg_stat_tmp

		check_result_msg="'$pkgname' is missing, must be installed to the rootstrap"
		return
	fi

	# package is not present in the rootstrap, but
	# it can be accepted from the host environment.
	run_in_tools_mode dpkg-query -s "$pkgname" >/dev/null 2>&1
	if [ $tools_mode_tool_stat == 0 ]; then
		installed_to_host="yes"
		check_result_msg="'$pkgname' found from the host environment"
		return
	fi

	# not installed. Test if this can be ignored.
	if [ -f $cfgfile_host_ignored_pkgs ]
	then
		g=`grep "^$pkgname\$" $cfgfile_host_ignored_pkgs`
		if [ -n "$g" ]
		then
			check_result_msg="'$pkgname' is not available (ignored by configuration)"
			installed_to_host="yes"
			return
		fi
	fi

	check_result_msg="'$pkgname' is missing (can be installed to the host)"
	return 1
}

function check_gcc_dependency()
{
	required_gcc=$1
	prefix="$2"

	if [ -f $HOME/.scratchbox2/$sbox_target/sb2.config.d/gcc.config.sh ]
	then
		# a cross compiler has been configured
		if [ "$required_gcc" = "gcc" ]
		then
			# requires GCC, but does not depend on gcc version
			echo "$prefix""SB2 provides gcc"
			return 0
		fi
		#
		# Find out if gcc version is suitable, try all configured
		# toolchains
		for gcc_conf_file in \
			$HOME/.scratchbox2/$sbox_target/sb2.config.d/gcc*.config.sh
		do
			if [ -f $gcc_conf_file ]; then
				. $gcc_conf_file
				short_vrs="gcc-$SBOX_CROSS_GCC_SHORTVERSION"
				full_vrs="gcc-$SBOX_CROSS_GCC_VERSION"
				if [ "$required_gcc" = "$short_vrs" -o \
				     "$required_gcc" = "$full_vrs" ]; then
					echo "$prefix""SB2 provides $required_gcc"
					return 0
				fi
			fi
		done
	fi # else a cross-compiler is not available, gcc comes from tools

	# Failed, SB2 environment does not provide a suitable gcc.
	return 1
}

function check_sb2_builddeps()
{
	orig_missing="$1"
	prefix="$2"

	new_missing=""
	ret=0

	# Currently, SB2 can fulfill "gcc" and "gcc-<version>"
	for m in $orig_missing
	do
		case $m in
		gcc*)	check_gcc_dependency "$m" "$prefix"
			if [ $? != 0 ]; then
				# gcc check failed
				new_missing="$new_missing $m"
			fi
			;;
		*)	# keep it in the list of missing pkgs
			new_missing="$new_missing $m"
			;;
		esac
	done

	missing_deps="$new_missing"

	if [ -z "$new_missing" ]; then
		# all resolved.
		true
	else
		# still missing something
		false
	fi
}


function check_host_builddeps()
{
	missing="$1"
	prefix="$2"
	ret=0

	# do the magic here
	echo "$prefix""SB2 Checking host build deps.."

	list_ok=1	# default to ok
	# $m will be the package to test, or pkg/pkg[/...] if there are
	# alternatives (unfortunately '|' has special meaning in shell's
	# "case" statement, so we'll have to replace it by '/')
	for m in $(echo $missing | sed -e 's/([^)]\+)//g' | \
		sed -e 's:[ 	]*|[ 	]*:/:g')
	do
		## echo "   Testing $m:"
		case "$m" in
		*/*)	# alternatives..
			has_one_alternative=0
			for mmm in $(echo $m | sed -e 's:/: :')
			do
				echo "$prefix""       ...$mmm"
				check_host_pkg $mmm
				if [ "$installed_to_host" = "yes" ]
				then
					echo "$prefix""       $mmm = ok"
					has_one_alternative=1
				else
					echo "$prefix""       no $mmm.."
				fi
			done
			if [ $has_one_alternative == 0 ]
			then
				echo "$prefix""     Requirement $m failed; none of the alternatives were found."
				list_ok=0
			else
                                echo "$prefix""     '$m': At least one alternative found, ok."
			fi
			;;

		*)	# No alternatives.
			check_host_pkg $m
			echo "$prefix""     $check_result_msg"
			if [ -n "$check_result_msg2" ]
			then
				echo "$prefix""     $check_result_msg2"
			fi
			if [ "$installed_to_host" = "no" ]
			then
				list_ok=0
			fi
		esac

	done

	if [ $list_ok == 0 ]; then
		# somethings missing
		false
	else
		true
	fi
}

function check_host_builddeps_by_real_tool()
{
	ret=0
	echo "SB2 Checking tools build deps..."
	x_missing_dep_file=`mktemp -p $SBOX_SESSION_DIR/tmp tools_missing_deps.XXXXXXXXXX`

	# Run dpkg-checkbuilddeps in the "tools" mode
	# Note: Can't use a pipeline here, we want to the
	# dpkg-checkbuilddeps' return status.
	run_in_tools_mode /usr/bin/dpkg-checkbuilddeps \
		$args > $x_missing_dep_file 2>&1
	if [ $tools_mode_tool_stat == 0 ]; then
		# real dpkg-checkbuilddeps says "all ok"
		rm $x_missing_dep_file
		tools_missing_deps=""
		return 0
	fi

	# else real dpkg-checkbuilddeps failed.
	# sed -e 's/^/     /' < $x_missing_dep_file
	tools_missing_deps=$(egrep \
		"^dpkg-checkbuilddeps: Unmet build dependencies:" \
			$x_missing_dep_file | \
		sed 's/dpkg-checkbuilddeps: Unmet build dependencies: //')
	rm $x_missing_dep_file

	if [ -n "$tools_missing_deps" ]; then
		# failing target deps, and missing packages are listed
		# in $tools_missing_deps = continue by checking if those are
		# available on the host environment
		return 1
	else
		# failing target deps, but $tools_missing_deps is empty. Something
		# is fatally wrong.
		echo "FATAL: Failed to check dependencies from tools_root DB"
		exit 1
	fi
}

function check_target_builddeps()
{
	ret=0
	echo "SB2 Checking target build deps..."
	missing_dep_file=`mktemp -p $SBOX_SESSION_DIR/tmp missing_deps.XXXXXXXXXX`

	# dpkg-checkbuilddeps with another package db..
	# a special rule in the tools mode is needed because the
	# version which is available in /usr/bin may not know about the
	# --admindir option. Can't use a pipeline here, we want to the
	# dpkg-checkbuilddeps' return status.
	SBOX_TOOLS_MODE_VAR_LIB_DPKG_STATUS_LOCATION=$TARGET_DPKG_ADMINDIR_USABLE_PKGS/status \
		run_in_tools_mode /usr/bin/dpkg-checkbuilddeps \
			$args > $missing_dep_file 2>&1
	if [ $tools_mode_tool_stat == 0 ]; then
		# real dpkg-checkbuilddeps says "all ok"
		rm $missing_dep_file
		return 0
	fi

	# else real dpkg-checkbuilddeps failed.
	sed -e 's/^/     /' < $missing_dep_file
	missing_deps=$(egrep \
		"^dpkg-checkbuilddeps: Unmet build dependencies:" \
			$missing_dep_file | \
		sed 's/dpkg-checkbuilddeps: Unmet build dependencies: //')
	rm $missing_dep_file

	if [ -n "$missing_deps" ]; then
		# failing target deps, and missing packages are listed
		# in $missing_deps = continue by checking if those are
		# available on the host environment
		return 1
	else
		# failing target deps, but $missing_deps is empty. Something
		# is fatally wrong.
		echo "FATAL: Failed to check dependencies from target_root DB"
		exit 1
	fi
}

function compare_target_and_host_results_with_new_tool() 
{
	t_missing=$missing_deps
	h_missing=$tools_missing_deps

	both_required=`cat $TARGET_DPKG_ADMINDIR_USABLE_PKGS/both-required`
	host_accepted=`grep -v "#" $cfgfile_host_accepted_pkgs`

	host_ignored=""
	if [ -f $cfgfile_host_ignored_pkgs ]
	then
		# ignorelist exists
		host_ignored=`grep -v "#" $cfgfile_host_ignored_pkgs`
	fi

	echo "SB2 Combining results from target and tools..."

	$sbox_dir/share/scratchbox2/lib/sb2-cmp-checkbuilddeps-output.pl \
		"$t_missing" "$h_missing" "$both_required" "$host_accepted" "$host_ignored"
	result2=$?
	return $result2
	#### if [ $? = 0 ]; then
	####	result2="ok"
	####else
	####	result2="fail"
	####fi
}

# First, make sure we are in a correct directory:
if [ ! -f debian/control ]
then
	echo "Error: Can't find file debian/control"
	exit 1
fi

# Next, check that the list of usable packages exists and is up-to-date.
# That list is really a temporary package database, which contains only
# packages that are usable thru this mapping mode.
sb2-check-pkg-mappings -u

check_target_builddeps
check_target_builddeps_result=$?
missing_deps_after_target_check="$missing_deps"

function old_deps_checker()
{
	if [ $check_target_builddeps_result == 0 ]; then
		# nothing is missing = nothing needed from the host side
		echo "OLD_CHK: Target rootstrap => all dependencies OK"
		return 0
	fi

	echo "OLD_CHK: Build dependencies missing from the target environment:"
	echo "OLD_CHK:      $missing_deps"

	# Something is missing. Check if SB2 can fulfill the requirements:
	check_sb2_builddeps "$missing_deps" "OLD_CHK: "
	if [ $? == 0 ]; then
		# OK now, nothing needed from the host side
		echo "OLD_CHK: SB2 tools check => all dependencies OK"
		return 0
	fi

	# Something is missing. To be able to get the missing packages from the
	# host environment, at least the list of allowed packages is needed:
	#
	if [ ! -f $cfgfile_host_accepted_pkgs ]
	then
		echo "OLD_CHK:"
		echo "OLD_CHK: Configuration file $cfgfile_host_accepted_pkgs"
		echo "OLD_CHK: does not exist. This means that no packages have been approved to be used"
		echo "OLD_CHK: from the host environment in this mapping mode ($sbox_mapmode)."
		return 1
	fi

	check_host_builddeps "$missing_deps" "OLD_CHK: "
	if [ $? != 0 ]; then
		echo "OLD_CHK: Failed. Host environment did not meet all requirements."
		return 1
	fi

	# since we're here, everything is more or less ok
	echo "OLD_CHK: All OK."
	return 0
}

function new_deps_checker()
{
	check_sb2_builddeps "$missing_deps" ""
	# $missing_deps has been updated

	check_host_builddeps_by_real_tool
	# $tools_missing_deps now contains a list of missing
	# packages, liste by the real dpkg-checkbuilddeps

	compare_target_and_host_results_with_new_tool
	new_deps_checker_result=$?
}

if [ -n "$SBOX_DOUBLECHECK_DEPS" ]; then
	old_deps_checker
	old_deps_checker_result=$?
fi

missing_deps="$missing_deps_after_target_check"
new_deps_checker

if [ -n "$SBOX_DOUBLECHECK_DEPS" ]; then
	if [ "$new_deps_checker_result" != "$old_deps_checker_result" ]; then
		echo "INCONSISTENT: new and old methods do not agree:"
		if [ "$new_deps_checker_result" = 0 ]; then
			echo "            : new => dependency checks OK"
		else
			echo "            : new => dependency checks FAILED"
		fi
		if [ "$old_deps_checker_result" = 0 ]; then
			echo "            : old => dependency checks OK"
		else
			echo "            : old => dependency checks FAILED"
		fi
		echo "Failed."
		exit 1
	fi
fi

if [ "$new_deps_checker_result" != "0" ]; then
	echo "Failed."
	exit 1
fi

# since we're here, everything is more or less ok
echo "All OK."
exit 0