epm-sh-functions 10.4 KB
Newer Older
Vitaly Lipatov's avatar
Vitaly Lipatov committed
1 2
#!/bin/sh
#
3 4
# Copyright (C) 2012, 2014  Etersoft
# Copyright (C) 2012, 2014  Vitaly Lipatov <lav@etersoft.ru>
Vitaly Lipatov's avatar
Vitaly Lipatov committed
5
#
6 7 8
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
Vitaly Lipatov's avatar
Vitaly Lipatov committed
9 10 11 12 13
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
# GNU Affero General Public License for more details.
Vitaly Lipatov's avatar
Vitaly Lipatov committed
15
#
16 17
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
Vitaly Lipatov's avatar
Vitaly Lipatov committed
18 19
#

20
# copied from /etc/init.d/outformat (ALT Linux)
21

22
# FIXME on Android: FIX ME! implement ttyname_r() bionic/libc/bionic/stubs.c:366
23 24 25
inputisatty()
{
	# check stdin
26 27
	#tty -s 2>/dev/null
	test -t 0
28 29
}

30 31
isatty()
{
32 33 34 35 36 37
	# check stdout
	test -t 1
}

isatty2()
{
Vitaly Lipatov's avatar
Vitaly Lipatov committed
38 39
	# check stderr
	test -t 2
40 41
}

42 43
check_tty()
{
44 45 46 47 48 49
	isatty2 || return

	# Set a sane TERM required for tput
	[ -n "$TERM" ] || TERM=dumb
	export TERM

50
	# egrep from busybox may not --color
Vitaly Lipatov's avatar
Vitaly Lipatov committed
51
	# egrep from MacOS print help to stderr
Vitaly Lipatov's avatar
Vitaly Lipatov committed
52
	if grep -E --help 2>&1 | grep -q -- "--color" ; then
53
		export EGREPCOLOR="--color"
54 55
	fi

56 57 58 59
	which tput >/dev/null 2>/dev/null || return
	# FreeBSD does not support tput -S
	echo | tput -S >/dev/null 2>/dev/null || return
	[ -z "$USETTY" ] || return
60 61 62
	export USETTY=1
}

63 64 65 66
: ${BLACK:=0} ${RED:=1} ${GREEN:=2} ${YELLOW:=3} ${BLUE:=4} ${MAGENTA:=5} ${CYAN:=6} ${WHITE:=7}

set_boldcolor()
{
67
	[ "$USETTY" = "1" ] || return
68 69 70 71 72 73 74 75
	{
		echo bold
		echo setaf $1
	} |tput -S
}

restore_color()
{
76
	[ "$USETTY" = "1" ] || return
77 78 79 80 81 82
	{
		echo op; # set Original color Pair.
		echo sgr0; # turn off all special graphics mode (bold in our case).
	} |tput -S
}

Vitaly Lipatov's avatar
Vitaly Lipatov committed
83 84
echover()
{
Vitaly Lipatov's avatar
Vitaly Lipatov committed
85
    [ -z "$verbose" ] && return
86
    echo "$*" >&2
Vitaly Lipatov's avatar
Vitaly Lipatov committed
87 88
}

89 90 91
# echo string without EOL
echon()
{
Vitaly Lipatov's avatar
Vitaly Lipatov committed
92
	# default /bin/sh on MacOS does not recognize -n
Vitaly Lipatov's avatar
Vitaly Lipatov committed
93
	/bin/echo -n "$*"
94 95 96
}


Vitaly Lipatov's avatar
Vitaly Lipatov committed
97 98 99
# Used DISTRNAME
set_target_pkg_env()
{
Vitaly Lipatov's avatar
Vitaly Lipatov committed
100
	[ -n "$DISTRNAME" ] || fatal "Missing DISTRNAME in set_target_pkg_env."
Vitaly Lipatov's avatar
Vitaly Lipatov committed
101 102 103 104 105 106
	PKGFORMAT=$($DISTRVENDOR -p "$DISTRNAME")
	PKGVENDOR=$($DISTRVENDOR -s "$DISTRNAME")
	RPMVENDOR=$($DISTRVENDOR -n "$DISTRNAME")
}

# Print command line and run command line
107
showcmd()
Vitaly Lipatov's avatar
Vitaly Lipatov committed
108
{
109 110 111
	if [ -z "$quiet" ] ; then
		set_boldcolor $GREEN
		local PROMTSIG="\$"
112
		[ "$EFFUID" = 0 ] && PROMTSIG="#"
Vitaly Lipatov's avatar
Vitaly Lipatov committed
113
		echo " $PROMTSIG $*"
114
		restore_color
115
	fi >&2
116 117 118 119 120
}

# Print command line and run command line
docmd()
{
Vitaly Lipatov's avatar
Vitaly Lipatov committed
121
	showcmd "$*$EXTRA_SHOWDOCMD"
122 123
#FIXME
	$@
Vitaly Lipatov's avatar
Vitaly Lipatov committed
124 125
}

126
# Run every arg with docmd
127 128
docmd_foreach()
{
129
	local cmd pkg
130 131 132 133
	cmd="$1"
	#showcmd "$@"
	shift
	for pkg in "$@" ; do
134
		docmd "$cmd" $pkg
135 136 137
	done
}

138
# Print command line and run command line with SUDO
139
sudocmd()
140
{
141
	[ -n "$SUDO" ] && showcmd "$SUDO $*" || showcmd "$*"
142
	$SUDO $@
143 144
}

145
# Run every arg with sudocmd
146
# Returns on any error
147 148
sudocmd_foreach()
{
149
	local cmd pkg
150 151 152 153
	cmd="$1"
	#showcmd "$@"
	shift
	for pkg in "$@" ; do
154
		sudocmd "$cmd" $pkg || return
155 156 157
	done
}

158 159 160 161 162 163 164 165
# add realpath if missed
if ! which realpath 2>/dev/null >/dev/null ; then
realpath()
{
	readlink -f "$@"
}
fi

166 167
get_firstarg()
{
168
	echon "$1"
169 170 171 172 173
}

get_lastarg()
{
	local lastarg
Vitaly Lipatov's avatar
Vitaly Lipatov committed
174
	eval "lastarg=\${$#}"
175
	echon "$lastarg"
176 177
}

178 179 180 181 182 183
# TODO: see etersoft-build-utils/tests/test_isnumber.sh
isnumber()
{
	echo "$*" | filter_strip_spaces | grep -q "^[0-9]\+$"
}

Vitaly Lipatov's avatar
Vitaly Lipatov committed
184 185 186 187 188 189 190 191 192 193 194 195 196
filter_strip_spaces()
{
        # possible use just
        #xargs echo
        sed -e "s| \+| |g" | \
                sed -e "s|^ ||" | sed -e "s| \$||"
}

strip_spaces()
{
        echo "$*" | filter_strip_spaces
}

197 198 199 200 201 202
# param true false
subst_option()
{
	eval "[ -n \"\$$1\" ]" && echo "$2" || echo "$3"
}

203 204 205 206
store_output()
{
    # use make_temp_file from etersoft-build-utils
    RC_STDOUT=$(mktemp)
207 208
    local CMDSTATUS=$RC_STDOUT.pipestatus
    echo 1 >$CMDSTATUS
209
    #RC_STDERR=$(mktemp)
210
    ( $@ 2>&1 ; echo $? >$CMDSTATUS ) | tee $RC_STDOUT
Vitaly Lipatov's avatar
Vitaly Lipatov committed
211
    return "$(cat $CMDSTATUS)"
212
    # bashism
213
    # http://tldp.org/LDP/abs/html/bashver3.html#PIPEFAILREF
214
    #return $PIPESTATUS
215 216
}

217 218 219 220 221 222
showcmd_store_output()
{
    showcmd "$@"
    store_output "$@"
}

223 224
clean_store_output()
{
225
    rm -f $RC_STDOUT $RC_STDOUT.pipestatus
226 227
}

228
# run epm, possible from side repo
229 230
epm()
{
231 232
	[ -n "$PROGNAME" ] || fatal "Can't use epm call from the piped script"
	$PROGDIR/$PROGNAME $@
233
}
Vitaly Lipatov's avatar
Vitaly Lipatov committed
234 235 236 237 238

# Print error message and stop the program
fatal()
{
	if [ -z "$TEXTDOMAIN" ] ; then
Vitaly Lipatov's avatar
Vitaly Lipatov committed
239
		echo "Error: $*" >&2
Vitaly Lipatov's avatar
Vitaly Lipatov committed
240 241
#	else
#		echog "Error in $0: $@" >&2
Vitaly Lipatov's avatar
Vitaly Lipatov committed
242 243 244
	fi
	exit 1
}
245

Vitaly Lipatov's avatar
Vitaly Lipatov committed
246 247 248 249
# Print warning message
warning()
{
	if [ -z "$TEXTDOMAIN" ] ; then
Vitaly Lipatov's avatar
Vitaly Lipatov committed
250
		echo "Warning: $*" >&2
Vitaly Lipatov's avatar
Vitaly Lipatov committed
251 252 253 254 255
#	else
#		echog "Error in $0: $@" >&2
	fi
}

256 257 258 259
info()
{
	[ -n "$quiet" ] && return

260 261 262
	# print message to stderr if stderr forwarded to (a file)
	if isatty2 ; then
		isatty || return 0
Vitaly Lipatov's avatar
Vitaly Lipatov committed
263
		echo "$*"
264
	else
Vitaly Lipatov's avatar
Vitaly Lipatov committed
265
		echo "$*" >&2
266
	fi
267 268
}

269 270
set_sudo()
{
271 272 273
	SUDO=""
	# skip SUDO if disabled
	[ -n "$EPMNOSUDO" ] && return
274 275 276 277
	if [ "$DISTRNAME" = "Cygwin" ] || [ "$DISTRNAME" = "Windows" ] ; then
		# skip sudo using on Windows
		return
	fi
278

Vitaly Lipatov's avatar
Vitaly Lipatov committed
279
	EFFUID=$(id -u)
280 281

	# do not need sudo
282
	[ $EFFUID = "0" ] && return
283 284

	# use sudo if possible
285 286
	if which sudo >/dev/null 2>/dev/null ; then
		SUDO="sudo --"
287
		# check for < 1.7 version which do not support -- (and --help possible too)
288
		sudo -h 2>/dev/null | grep -q "  --" || SUDO="sudo"
289 290
		return
	fi
291 292

	SUDO="fatal 'Can't find sudo. Please install sudo or run epm under root.'"
293 294
}

295 296
# wait for n seconds (if possible) during executing command
# args: seconds command
297 298 299
withtimeout()
{
	local TO=$(which timeout 2>/dev/null || which gtimeout 2>/dev/null)
Vitaly Lipatov's avatar
Vitaly Lipatov committed
300
	if [ -x "$TO" ] ; then
301
		$TO "$@"
Vitaly Lipatov's avatar
Vitaly Lipatov committed
302 303 304
		return
	fi
	# fallback: drop time arg and run without timeout
305
	shift
306
	"$@"
307 308
}

309 310 311 312 313 314
set_eatmydata()
{
	# skip if disabled
	[ -n "$EPMNOEATMYDATA" ] && return
	# use if possible
	which eatmydata >/dev/null 2>/dev/null || return
315
	[ -n "$SUDO" ] && SUDO="$SUDO eatmydata" || SUDO="eatmydata"
316
	[ -n "$verbose" ] && info "Uwaga! eatmydata is installed, we will use it for disable all sync operations."
Vitaly Lipatov's avatar
Vitaly Lipatov committed
317
	return 0
318 319
}

320 321
# 
__get_package_for_command()
322
{
323
	case "$1" in
324
		equery|revdep-rebuild)
325
			echo 'gentoolkit'
326
			;;
327
		update-kernel|remove-old-kernels)
328
			echo 'update-kernel'
329 330 331 332
			;;
	esac
}

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
# TODO:
confirm() {
    local response
    # call with a prompt string or use a default
    read -r -p "${1:-Are you sure? [y/N]} " response
    case $response in
        [yY][eE][sS]|[yY])
            true
            ;;
        *)
            false
            ;;
    esac
}

assure_root()
{
	[ "$EFFUID" = 0 ] || fatal "run me only under root"
}

regexp_subst()
{
	local expression="$1"
	shift
	sed -i -r -e "$expression" "$@"
}

Vitaly Lipatov's avatar
Vitaly Lipatov committed
360
# TODO: we we can't use epm directly?
361 362 363
assure_exists()
{
	load_helper epm-assure
Vitaly Lipatov's avatar
Vitaly Lipatov committed
364
	local package="$2"
365
	local textpackage=
Vitaly Lipatov's avatar
Vitaly Lipatov committed
366
	[ -n "$package" ] || package="$(__get_package_for_command "$1")"
367 368
	[ -n "$3" ] && textpackage=" >= $3"
	__epm_assure "$1" $package $3 || fatal "Can't assure in '$1' command from $package$textpackage package"
369 370
}

371
# will replaced within disabled_eget in packaged version
Vitaly Lipatov's avatar
Vitaly Lipatov committed
372
eget()
373 374 375 376 377 378 379 380 381 382 383 384 385
{
	# use internal eget only if exists
	if [ -s $SHAREDIR/tools_eget ] ; then
		$SHAREDIR/tools_eget "$@"
		return
	fi

	assure_exists eget
	# run external command, not the function
	EGET=$(which eget) || fatal "Missed command eget from installed package eget"
	$EGET "$@"
}

Vitaly Lipatov's avatar
Vitaly Lipatov committed
386 387 388 389 390 391 392 393 394 395 396 397 398 399
estrlist()
{
	if [ -s $SHAREDIR/tools_estrlist ] ; then
		$SHAREDIR/tools_estrlist "$@"
		return
	fi
	fatal "missed tools_estrlist"
}

onefile_estrlist()
{
	internal_tools_estrlist "$@"
}

400 401
# will replaced within eget() in packed version
onefile_eget()
Vitaly Lipatov's avatar
Vitaly Lipatov committed
402
{
Vitaly Lipatov's avatar
Vitaly Lipatov committed
403
	assure_exists wget
404
	internal_tools_eget "$@"
Vitaly Lipatov's avatar
Vitaly Lipatov committed
405 406
}

407
# TODO: improve and drop!
408 409 410
get_package_type()
{
	local i
411 412 413 414 415 416 417 418 419
	case $1 in
		*.deb)
			echo "deb"
			return
			;;
		*.rpm)
			echo "rpm"
			return
			;;
420 421 422 423 424 425 426 427
		*.txz)
			echo "txz"
			return
			;;
		*.tbz)
			echo "tbz"
			return
			;;
428 429 430 431
		*.exe)
			echo "exe"
			return
			;;
432 433 434 435
		*.msi)
			echo "msi"
			return
			;;
436 437 438 439 440 441 442
		*)
			#fatal "Don't know type of $1"
			# return package name for info
			echo "$1"
			return 1
			;;
	esac
443 444 445
}


446 447 448
# print options description from HELPCMD/HELPOPT lines in the code
get_help()
{
449 450 451 452
    if [ "$0" = "/dev/stdin" ] || [ "$0" = "sh" ] ; then
        return
    fi

Vitaly Lipatov's avatar
Vitaly Lipatov committed
453
    grep -v -- "^#" $0 | grep -- "# $1" | while read -r n ; do
454 455 456 457 458 459
        opt=$(echo $n | sed -e "s|) # $1:.*||g")
        desc=$(echo $n | sed -e "s|.*) # $1:||g")
        printf "    %-20s %s\n" $opt "$desc"
    done
}

460

461 462 463 464
# FIXME: detect if not recognized
set_pm_type()
{
	local CMD
465 466 467

	# Fill for use: PMTYPE, DISTRNAME, DISTRVERSION, PKGFORMAT, PKGVENDOR, RPMVENDOR
	DISTRVENDOR=$PROGDIR/distr_info
468
	[ -n "$DISTRNAME" ] || DISTRNAME=$($DISTRVENDOR -d) || fatal "Can't get distro name."
469 470 471
	[ -n "$DISTRVERSION" ] || DISTRVERSION=$($DISTRVENDOR -v)
	set_target_pkg_env

472 473 474 475 476 477
# override package manager detection result
if [ -n "$FORCEPM" ] ; then
	PMTYPE=$FORCEPM
	return
fi

478 479
# TODO: move it in distr_vendor?
# FIXME: some problems with multibased distros (Server Edition on CentOS and Desktop Edition on Ubuntu)
480
case $DISTRNAME in
481
	ALTLinux)
482
		CMD="apt-rpm"
483
		#which ds-install 2>/dev/null >/dev/null && CMD=deepsolver-rpm
484 485
		;;
	PCLinux)
486 487
		CMD="apt-rpm"
		;;
488
	Ubuntu|Debian|Mint|AstraLinux|Elbrus)
489
		CMD="apt-dpkg"
Vitaly Lipatov's avatar
Vitaly Lipatov committed
490
		#which aptitude 2>/dev/null >/dev/null && CMD=aptitude-dpkg
491
		which snappy 2>/dev/null >/dev/null && CMD=snappy
492
		;;
Vitaly Lipatov's avatar
Vitaly Lipatov committed
493
	Mandriva|ROSA)
494 495
		CMD="urpm-rpm"
		;;
496 497
	FreeBSD|NetBSD|OpenBSD|Solaris)
		CMD="pkgsrc"
498
		which pkg 2>/dev/null >/dev/null && CMD=pkgng
499
		;;
500 501 502
	Gentoo)
		CMD="emerge"
		;;
503 504 505
	ArchLinux)
		CMD="pacman"
		;;
506
	Fedora|LinuxXP|ASPLinux|CentOS|RHEL|Scientific|GosLinux|Amzn)
507
		CMD="yum-rpm"
508
		which dnf 2>/dev/null >/dev/null && test -d /var/lib/dnf/yumdb && CMD=dnf-rpm
509
		;;
510
	Slackware)
511
		CMD="slackpkg"
512
		;;
513
	SUSE|SLED|SLES|Tumbleweed)
514 515
		CMD="zypper-rpm"
		;;
516 517 518
	ForesightLinux|rPathLinux)
		CMD="conary"
		;;
519
	Windows)
520
		CMD="chocolatey"
521
		;;
522 523 524
	MacOS)
		CMD="homebrew"
		;;
525 526
	OpenWrt)
		CMD="opkg"
527
		;;
528 529 530
	GNU/Linux/Guix)
		CMD="guix"
		;;
531 532 533
	Android)
		CMD="android"
		;;
534 535 536
	Cygwin)
		CMD="aptcyg"
		;;
537 538 539
	alpine)
		CMD="apk"
		;;
540 541 542
	TinyCoreLinux)
		CMD="tce"
		;;
543 544 545
	VoidLinux)
		CMD="xbps"
		;;
546
	*)
547
		fatal "Have no suitable DISTRNAME $DISTRNAME"
548 549 550 551
		;;
esac
PMTYPE=$CMD
}
552

553 554 555 556 557 558 559 560

is_active_systemd()
{
	local a
	SYSTEMCTL=/bin/systemctl
	SYSTEMD_CGROUP_DIR=/sys/fs/cgroup/systemd
	[ -x "$SYSTEMCTL" ] || return
	[ -d "$SYSTEMD_CGROUP_DIR" ] || return
Vitaly Lipatov's avatar
Vitaly Lipatov committed
561
	a='' mountpoint -q "$SYSTEMD_CGROUP_DIR" || return
562
	readlink /sbin/init | grep -q 'systemd' || return
563
	# some hack
Vitaly Lipatov's avatar
Vitaly Lipatov committed
564
	# shellcheck disable=SC2009
565
	ps ax | grep '[s]ystemd' | grep -q -v 'systemd-udev'
566
}
567 568 569 570 571 572 573

assure_distr()
{
	local TEXT="this option"
	[ -n "$2" ] && TEXT="$2"
	[ "$DISTRNAME" = "$1" ] || fatal "$TEXT supported only for $1 distro"
}