epm-sh-functions 24.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

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

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

isatty2()
{
39 40
    # check stderr
    test -t 2
41 42
}

43 44
check_tty()
{
45
    isatty2 || return
46

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

51
    check_core_commands
52

53 54 55 56 57
    # grep -E from busybox may not --color
    # grep -E from MacOS print help to stderr
    if grep -E --help 2>&1 | grep -q -- "--color" ; then
        export EGREPCOLOR="--color"
    fi
58

59 60 61 62
    is_command tput || return
    # FreeBSD does not support tput -S
    echo | a= tput -S >/dev/null 2>/dev/null || return
    USETTY="tput -S"
63 64
}

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

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

76 77
set_color()
{
78 79 80 81
    [ -n "$USETTY" ] || return
    {
        echo setaf $1
    } | $USETTY
82 83
}

84 85
restore_color()
{
86 87 88 89 90
    [ -n "$USETTY" ] || return
    {
        echo op; # set Original color Pair.
        echo sgr0; # turn off all special graphics mode (bold in our case).
    } | $USETTY
91 92
}

Vitaly Lipatov's avatar
Vitaly Lipatov committed
93 94
echover()
{
Vitaly Lipatov's avatar
Vitaly Lipatov committed
95
    [ -z "$verbose" ] && return
96
    echog "$*" >&2
Vitaly Lipatov's avatar
Vitaly Lipatov committed
97 98
}

99 100 101
# echo string without EOL
echon()
{
102 103
    # default /bin/sh on MacOS does not recognize -n
    echo -n "$*" 2>/dev/null || a= /bin/echo -n "$*"
104 105 106
}


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

119 120 121
# Print command
echocmd()
{
122 123 124 125 126
    set_boldcolor $GREEN
    local PROMTSIG="\$"
    is_root && PROMTSIG="#"
    echo -n "$PROMTSIG $*"
    restore_color
127 128
}

129 130 131
# Print command line and run command line
docmd()
{
132 133
    showcmd "$*$EXTRA_SHOWDOCMD"
    "$@"
Vitaly Lipatov's avatar
Vitaly Lipatov committed
134 135
}

136
# Run every arg with docmd
137 138
docmd_foreach()
{
139 140 141 142 143 144 145
    local cmd pkg
    cmd="$1"
    #showcmd "$@"
    shift
    for pkg in "$@" ; do
        docmd $cmd $pkg
    done
146 147
}

148 149 150
# run command line with SUDO
sudorun()
{
151 152 153 154 155 156
    set_sudo
    if [ -z "$SUDO" ] ; then
        "$@"
        return
    fi
    $SUDO "$@"
157 158
}

159
# Print command line and run command line with SUDO
160
sudocmd()
161
{
162 163 164
    set_sudo
    [ -n "$SUDO" ] && showcmd "$SUDO $*" || showcmd "$*"
    sudorun "$@"
165 166
}

167
# Run every arg with sudocmd
168
# Returns on any error
169 170
sudocmd_foreach()
{
171 172 173 174 175 176 177 178
    local cmd pkg
    cmd="$1"
    #showcmd "$@"
    shift
    for pkg in "$@" ; do
        # don't quote $cmd here: it can be a command with an args
        sudocmd $cmd $pkg || return
    done
179 180
}

181 182 183
# print full path to files
make_filepath()
{
184 185 186 187 188 189
    local i
    for i in "$@" ; do
        [ -f "$i" ] || continue
        echo "$i" | grep -q "/" && echo "$i" && continue
        echo "./$i"
    done
190 191
}

192 193
get_firstarg()
{
194
    echon "$1"
195 196 197 198
}

get_lastarg()
{
199 200 201
    local lastarg
    eval "lastarg=\${$#}"
    echon "$lastarg"
202 203
}

204 205 206
# TODO: see etersoft-build-utils/tests/test_isnumber.sh
isnumber()
{
207
    echo "$*" | filter_strip_spaces | grep -q "^[0-9]\+$"
208 209
}

Vitaly Lipatov's avatar
Vitaly Lipatov committed
210 211
# copied from strings
# CHECKME: the same like estrlist has ?
Vitaly Lipatov's avatar
Vitaly Lipatov committed
212
# Note: used grep -E! write '[0-9]+(first|two)', not '[0-9]\+...'
Vitaly Lipatov's avatar
Vitaly Lipatov committed
213 214
rhas()
{
215
    echo "$1" | grep -E -q -- "$2"
Vitaly Lipatov's avatar
Vitaly Lipatov committed
216 217
}

218 219 220 221 222
rihas()
{
    echo "$1" | grep -E -i -q -- "$2"
}

223 224 225 226 227 228 229 230 231 232 233 234 235
# bash specific
startwith()
{
    # rhas "$1" "^$2"
    [[ "$1" = ${2}* ]]
}

is_abs_path()
{
    #echo "$1" | grep -q "^/"
    startwith "$1" "/"
}

Vitaly Lipatov's avatar
Vitaly Lipatov committed
236 237 238 239
# copied from strings
is_dirpath()
{
    [ "$1" = "." ] && return $?
240 241
    # rhas "$1" "/"
    startwith "$1" "/"
Vitaly Lipatov's avatar
Vitaly Lipatov committed
242 243
}

244 245 246 247 248 249
is_wildcard()
{
    echo "$1" | grep -q "[*?]" && return
    echo "$1" | grep -q "\]" && return
    echo "$1" | grep -q "\[" && return
}
250

Vitaly Lipatov's avatar
Vitaly Lipatov committed
251 252 253 254 255 256 257 258 259 260 261 262 263
filter_strip_spaces()
{
        # possible use just
        #xargs echo
        sed -e "s| \+| |g" | \
                sed -e "s|^ ||" | sed -e "s| \$||"
}

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

264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
firstupper()
{
    # FIXME: works with GNU sed only
    echo "$*" | sed 's/.*/\u&/'
}

tolower()
{
    # tr is broken in busybox (checked with OpenWrt)
    #echo "$*" | tr "[:upper:]" "[:lower:]"
    echo "$*" | awk '{print tolower($0)}'
}

firstword()
{
        echo "$*" | cut -f1 -d" "
}

lastword()
{
        echo "$*" | xargs -n1 echo 2>/dev/null | tail -n1
}
286 287 288 289 290 291

# https://superuser.com/questions/422459/substitution-in-text-file-without-regular-expressions
# http://stackoverflow.com/a/2705678/120999
# use for subst complex string with symbols treating as regexp
sed_escape()
{
292
    echo "$*" | sed -e 's/[]()$*.^|[]/\\&/g'
293 294 295
}


296 297 298
# param true false
subst_option()
{
299
    eval "[ -n \"\$$1\" ]" && echo "$2" || echo "$3"
300 301
}

302 303 304
store_output()
{
    # use make_temp_file from etersoft-build-utils
305
    RC_STDOUT="$(mktemp)" || fatal
306
    remove_on_exit $RC_STDOUT
307 308
    local CMDSTATUS=$RC_STDOUT.pipestatus
    echo 1 >$CMDSTATUS
309
    #RC_STDERR=$(mktemp)
310
    ( LC_ALL=C $@ 2>&1 ; echo $? >$CMDSTATUS ) | tee $RC_STDOUT
Vitaly Lipatov's avatar
Vitaly Lipatov committed
311
    return "$(cat $CMDSTATUS)"
312
    # bashism
313
    # http://tldp.org/LDP/abs/html/bashver3.html#PIPEFAILREF
314
    #return $PIPESTATUS
315 316
}

317 318 319 320 321 322
showcmd_store_output()
{
    showcmd "$@"
    store_output "$@"
}

323 324
clean_store_output()
{
325
    rm -f $RC_STDOUT $RC_STDOUT.pipestatus
326 327
}

328
# run epm, possible from side repo
329 330
epm()
{
331
    if [ "$EPMMODE" = "pipe" ] ; then
332
        epm_main --inscript "$@"
333
        return
334
    fi
335 336 337

    # run epm again to full initialization
    local bashopt=''
338
    [ -n "$debug" ] && bashopt='-x'
339 340

    $CMDSHELL $bashopt $PROGDIR/$PROGNAME --inscript "$@"
341 342 343 344 345
}

# run $SUDO epm, possible from side repo
sudoepm()
{
346
    [ "$EPMMODE" = "pipe" ] && fatal "Can't use sudo epm call from the piped script"
347

348
    local bashopt=''
349
    [ -n "$debug" ] && bashopt='-x'
350

351
    sudorun $CMDSHELL $bashopt $PROGDIR/$PROGNAME --inscript "$@"
352
}
Vitaly Lipatov's avatar
Vitaly Lipatov committed
353

354 355 356 357
echog()
{
	if [ "$1" = "-n" ] ; then
		shift
358
		[ -n "$1" ] && eval_gettext "$*"
359
	else
360 361
		[ -n "$1" ] && eval_gettext "$*"
		echo
362 363 364
	fi
}

365 366 367 368
message()
{
    echog "$*"
}
369

Vitaly Lipatov's avatar
Vitaly Lipatov committed
370 371 372
# Print error message and stop the program
fatal()
{
373 374
    local PROMOMESSAGE="$EPMPROMOMESSAGE"
    [ -n "$PROMOMESSAGE" ] || PROMOMESSAGE=" (you can discuss the epm $EPMVERSION problem in Telegram: https://t.me/useepm)"
375 376 377 378 379

    set_color $RED >&2
    echog -n "ERROR: " >&2
    restore_color >&2
    echog "$* $PROMOMESSAGE" >&2
380 381
#    [ "$TERM" = "screen" ] && echo "(screen detected: waiting ten seconds to exit ...)" >&2 && sleep 10
    exit 1
Vitaly Lipatov's avatar
Vitaly Lipatov committed
382
}
383

384 385 386 387 388 389 390 391 392 393 394 395 396 397
# Print error message and stop the program, skippimg translate
fixme()
{
    local PROMOMESSAGE="$EPMPROMOMESSAGE"
    [ -n "$PROMOMESSAGE" ] || PROMOMESSAGE=" (you can discuss the epm $EPMVERSION problem in Telegram: https://t.me/useepm)"

    set_color $RED >&2
    echo -n "ERROR: " >&2
    restore_color >&2
    echo "$* $PROMOMESSAGE" >&2
#    [ "$TERM" = "screen" ] && echo "(screen detected: waiting ten seconds to exit ...)" >&2 && sleep 10
    exit 1
}

398 399 400 401
# Print debug message
debug()
{
    [ -n "$debug" ] || return
402 403 404 405 406

    set_color $YELLOW >&2
    echog -n "WARNING: " >&2
    restore_color >&2
    echog "$*" >&2
407 408 409
}


Vitaly Lipatov's avatar
Vitaly Lipatov committed
410 411 412
# Print warning message
warning()
{
413 414 415 416
    set_color $YELLOW >&2
    echog -n "WARNING: " >&2
    restore_color >&2
    echog "$*" >&2
Vitaly Lipatov's avatar
Vitaly Lipatov committed
417 418
}

419 420
info()
{
421
    [ -n "$quiet" ] && return
422

423 424 425
    # print message to stderr if stderr forwarded to (a file)
    if isatty2 ; then
        isatty || return 0
426
        echog "$*"
427
    else
428
        echog "$*" >&2
429
    fi
430 431
}

432 433 434

check_su_root()
{
435
    #[ "$BASEDISTRNAME" = "alt" ] || return 0
436 437 438 439 440 441 442 443 444

    is_root || return 0

    echo "$PATH" | grep -q "/usr/sbin" && return 0

    fatal "There is missed /usr/sbin path in PATH. Probably you have used 'su' without '-' to get root access. Use 'esu' or 'su -' command to get root permissions."
}


445 446 447
# if we have not sudo, returns 1 and set SUDO variable to fatal
SUDO_TESTED=''
SUDO_CMD='sudo'
448 449
set_sudo()
{
450 451 452 453 454 455 456 457 458 459 460 461 462 463
    local nofail="$1"

    # cache the result
    [ -n "$SUDO_TESTED" ] && return "$SUDO_TESTED"
    SUDO_TESTED="0"

    SUDO=""
    # skip SUDO if disabled
    [ -n "$EPMNOSUDO" ] && return
    if [ "$DISTRNAME" = "Cygwin" ] || [ "$DISTRNAME" = "Windows" ] ; then
        # skip sudo using on Windows
        return
    fi

464 465
    check_su_root

466 467 468 469 470 471
    # if we are root, do not need sudo
    is_root && return

    # start error section
    SUDO_TESTED="1"

472
    if is_command doas && a='' doas -C /etc/doas.conf > /dev/null 2>&1 ; then
473 474 475 476 477
        SUDO="doas"
        SUDO_TESTED="0"
        return "$SUDO_TESTED"
    fi

478
    if ! is_command $SUDO_CMD ; then
479
        [ "$nofail" = "nofail" ] || SUDO="fatal 'For this operation run epm under root, or install and tune sudo (http://altlinux.org/sudo)'"
480
        SUDO_TESTED="2"
481 482 483 484 485
        return "$SUDO_TESTED"
    fi

    # if input is a console
    if inputisatty && isatty && isatty2 ; then
486 487 488
        if ! $SUDO_CMD -n true ; then
            info "Please enter sudo user password to use sudo in the current session."
            if ! $SUDO_CMD -l >/dev/null ; then
489
                [ "$nofail" = "nofail" ] || SUDO="fatal 'For this operation run epm under root, or install and tune sudo (http://altlinux.org/sudo)'"
490
                SUDO_TESTED="3"
491 492
                return "$SUDO_TESTED"
            fi
493 494
        fi
    else
495
        # TODO: check user_can_sudo in https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh
496
        # use sudo if one is tuned and tuned without password
497 498
        # hack: check twice
        $SUDO_CMD -l -n >/dev/null 2>/dev/null
499
        if ! $SUDO_CMD -l -n >/dev/null 2>/dev/null ; then
500
            [ "$nofail" = "nofail" ] || SUDO="fatal 'Can't use sudo (only passwordless sudo is supported here). Please run epm under root or check http://altlinux.org/sudo '"
501
            SUDO_TESTED="4"
502 503 504 505 506 507 508 509 510 511
            return "$SUDO_TESTED"
        fi
    fi

    SUDO_TESTED="0"
    # FIXME: does not work: sudo -- VARIABLE=some command
    SUDO="$SUDO_CMD"
    #SUDO="$SUDO_CMD --"
    # check for < 1.7 version which do not support -- (and --help possible too)
    #$SUDO_CMD -h 2>/dev/null | grep -q "  --" || SUDO="$SUDO_CMD"
512

513 514
}

515 516 517
# return TRUE if we can run privileged command
sudo_allowed()
{
518
    set_sudo nofail
519 520
}

521 522
# wait for n seconds (if possible) during executing command
# args: seconds command
523 524
withtimeout()
{
525 526 527 528 529 530 531 532 533
    local TO=$(print_command_path timeout || print_command_path gtimeout)
    if [ -x "$TO" ] ; then
        $TO "$@"
        return
    fi
    fatal "Possible indefinite wait due timeout command is missed"
    # fallback: drop time arg and run without timeout
    #shift
    #"$@"
534 535
}

536 537
set_eatmydata()
{
538 539 540 541 542 543 544 545 546 547 548
    # don't use eatmydata (useless)
    return 0
    # skip if disabled
    [ -n "$EPMNOEATMYDATA" ] && return
    # use if possible
    is_command eatmydata || return
    set_sudo
    # FIXME: check if SUDO already has eatmydata
    [ -n "$SUDO" ] && SUDO="$SUDO eatmydata" || SUDO="eatmydata"
    [ -n "$verbose" ] && info "Uwaga! eatmydata is installed, we will use it for disable all sync operations."
    return 0
549 550
}

551 552
# 
__get_package_for_command()
553
{
554 555 556 557 558 559 560 561
    case "$1" in
        equery|revdep-rebuild)
            echo 'gentoolkit'
            ;;
        update-kernel|remove-old-kernels)
            echo 'update-kernel'
            ;;
    esac
562 563
}

564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
# 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
}

579 580 581

confirm_info()
{
582
    info "$*" >&2
583 584 585
    if [ -z "$non_interactive" ] ; then
        confirm "Are you sure? [y/N]" || fatal "Exiting"
    fi
586 587 588 589

}


590 591
is_root()
{
592 593
    local EFFUID="$(id -u)"
    [ "$EFFUID" = "0" ]
594 595
}

596 597
assure_root()
{
598
    is_root || fatal "run me only under root"
599 600
}

601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617
check_su_access()
{
    is_command su && return
    [ ! -f /bin/su ] && warning "/bin/su is missed. Try install su package (http://altlinux.org/su)." && return 1
    local group="$(stat -c '%G' /bin/su)" || fatal
    warning "Check if you are in $group group to have access to su command."
    return 1
}

check_sudo_access()
{
    is_command sudo && return
    local cmd=''
    local i
    for i in /bin/sudo /usr/bin/sudo ; do
        [ -f $i ] && cmd="$i"
    done
618 619
    [ ! -f "$cmd" ] && warning "sudo command is missed. Try install sudo package (http://altlinux.org/sudo)." && return 1
    local group="$(stat -c '%G' "$cmd")" || fatal
620 621 622 623 624 625 626 627 628 629 630 631
    warning "Check if you are in $group group to have access to sudo command."
    return 1
}

check_sudo_access_only()
{
    is_command sudo && return
    local cmd=''
    local i
    for i in /bin/sudo /usr/bin/sudo ; do
        [ -f $i ] && cmd="$i"
    done
632 633
    [ ! -f "$cmd" ] && return 1
    local group="$(stat -c '%G' "$cmd")" || fatal
634 635 636 637
    warning "sudo command is presence, but is not accessible for you. Check if you are in $group group to have access to sudo command."
    return 1
}

638 639 640 641 642 643 644 645 646
esu()
{
    if is_root ; then
        if [ -n "$*" ] ; then
            [ -n "$quiet" ] || showcmd "$*"
            exec "$@"
        else
            # just shell
            showcmd "su -"
647
            a= exec su -
648 649 650 651 652 653
        fi
    fi

    set_pm_type


Vitaly Lipatov's avatar
Vitaly Lipatov committed
654 655 656 657 658 659 660
# TODO:
#quote() {
#    for arg in "$@"; do
#        printf '%s\n' "$arg" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/'/"
#    done
#}

661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676
    escape_args()
    {
        local output=''
        while [ -n "$1" ] ; do
            if has_space "$1" ; then
                [ -n "$output" ] && output="$output '$1'" || output="'$1'"
            else
                [ -n "$output" ] && output="$output $1" || output="$1"
            fi
            shift
        done
        echo "$output"
    }

    escaped="$(escape_args "$@")"

677
    check_sudo_access_only
678 679
    # sudo is not accessible, will ask root password
    if ! set_sudo ; then
680
        check_su_access
681 682 683
        #info "Enter root password:"
        if [ -n "$*" ] ; then
            [ -n "$quiet" ] || showcmd "su - -c $escaped"
684
            a= exec su - -c "$escaped"
685 686 687
        else
            # just shell
            showcmd "su -"
688
            a= exec su -
689 690 691
        fi
    fi

692 693
    check_sudo_access

694 695 696 697 698 699 700 701 702 703
    #info "You can be asked about your password:"
    if [ -n "$*" ] ; then
        [ -n "$quiet" ] || showcmd "$SUDO su - -c $escaped"
        $SUDO su - -c "$escaped"
    else
        showcmd "$SUDO su -"
        $SUDO su -
    fi
}

704 705
regexp_subst()
{
706 707 708
    local expression="$1"
    shift
    sed -i -r -e "$expression" "$@"
709 710
}

711 712
# TODO: why we can't use epm directly?
try_assure_exists()
713
{
714 715 716
    load_helper epm-assure
    local package="$2"
    [ -n "$package" ] || package="$(__get_package_for_command "$1")"
717 718 719 720 721

    # ask for install: https://bugzilla.altlinux.org/42240
    local ask=''
    [ -n "$non_interactive" ] || ask=1

722 723 724 725 726 727
    ( verbose='' direct='' interactive=$ask epm_assure "$1" $package $3 )
}

assure_exists()
{
    try_assure_exists "$@" || fatal
728 729
}

730

731 732
assure_exists_erc()
{
733 734 735
    load_helper epm-assure
    local package="erc"
    ( direct='' epm_assure "$package" ) || epm ei erc || fatal "erc is not available to install."
736 737
}

738
# will replaced within disabled_eget in packaged version
Vitaly Lipatov's avatar
Vitaly Lipatov committed
739
eget()
740
{
741 742
    # use internal eget only if exists
    if [ -s $SHAREDIR/tools_eget ] ; then
743
        ( EGET_BACKEND=$eget_backend $CMDSHELL $SHAREDIR/tools_eget "$@" )
744 745 746
        return
    fi
    fatal "Internal error: missed tools_eget"
747

Vitaly Lipatov's avatar
Vitaly Lipatov committed
748
    local EGET
749 750 751 752 753
    # FIXME: we need disable output here, eget can be used for get output
    assure_exists eget eget 3.3 >/dev/null
    # run external command, not the function
    EGET=$(print_command_path eget) || fatal "Missed command eget from installed package eget"
    $EGET "$@"
754 755
}

756

757 758
__epm_assure_7zip()
{
759 760 761 762
    # install 7zip in any case (can be used)
    if is_command 7z || is_command 7za || is_command 7zr || is_command 7zz ; then
        :
    else
763
        epm install 7-zip || epm install p7zip
764
    fi
765 766 767 768 769 770
}

# will replaced within disabled_erc in packaged version
erc()
{

Vitaly Lipatov's avatar
Vitaly Lipatov committed
771
    __epm_assure_7zip
772

773 774
    # use internal eget only if exists
    if [ -s $SHAREDIR/tools_erc ] ; then
775
        $CMDSHELL $SHAREDIR/tools_erc "$@"
776 777 778
        return
    fi
    fatal "Internal error: missed tools_erc"
779

780 781 782
    # FIXME: we need disable output here, ercat can be used for get output
    assure_exists_erc >/dev/null
    # run external command, not the function
783
    local ERC
784 785
    ERC=$(print_command_path erc) || fatal "Missed command erc from installed package erc"
    $ERC "$@"
786 787 788 789 790
}

# will replaced within disabled_ercat in packaged version
ercat()
{
791 792 793
    local ERCAT
    # use internal eget only if exists
    if [ -s $SHAREDIR/tools_ercat ] ; then
794
        $CMDSHELL $SHAREDIR/tools_ercat "$@"
795 796 797
        return
    fi
    fatal "Internal error: missed tools_ercat"
798

799 800 801 802 803
    # FIXME: we need disable output here, ercat can be used for get output
    assure_exists_erc >/dev/null
    # run external command, not the function
    ERCAT=$(print_command_path ercat) || fatal "Missed command ercat from installed package erc"
    $ERCAT "$@"
804 805
}

Vitaly Lipatov's avatar
Vitaly Lipatov committed
806 807
estrlist()
{
808
    if [ -s $SHAREDIR/tools_estrlist ] ; then
809
        $CMDSHELL $SHAREDIR/tools_estrlist "$@"
810 811 812
        return
    fi
    fatal "missed tools_estrlist"
Vitaly Lipatov's avatar
Vitaly Lipatov committed
813 814 815 816
}

onefile_estrlist()
{
817
    internal_tools_estrlist "$@"
Vitaly Lipatov's avatar
Vitaly Lipatov committed
818 819
}

820 821
# will replaced within eget() in packed version
onefile_eget()
Vitaly Lipatov's avatar
Vitaly Lipatov committed
822
{
823 824
    # check for both
    # we really need that cross here,
825 826
    is_command curl || try_assure_exists wget
    is_command wget || try_assure_exists curl
827
    internal_tools_eget "$@"
Vitaly Lipatov's avatar
Vitaly Lipatov committed
828 829
}

830
# TODO: improve and drop!
831 832
get_package_type()
{
833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858
    local i
    case $1 in
        *.deb)
            echo "deb"
            return
            ;;
        *.rpm)
            echo "rpm"
            return
            ;;
        *.txz)
            echo "txz"
            return
            ;;
        *.tbz)
            echo "tbz"
            return
            ;;
        *.exe)
            echo "exe"
            return
            ;;
        *.msi)
            echo "msi"
            return
            ;;
859
        *.AppImage|*.appimage)
860 861 862 863
            echo "AppImage"
            return
            ;;
        *)
864
            if [ -r "$1" ] && file -L "$1" | grep -q " ELF " ; then
865 866 867
                echo "ELF"
                return
            fi
868
            # print extension by default
869
            basename "$1" | sed -e 's|.*\.||'
870 871 872
            return 1
            ;;
    esac
873 874 875
}


876
# print options description from HELPCMD/HELPOPT lines in the code
877
# args: section_name, [file with code]
878 879
get_help()
{
880 881 882
    if [ "$0" = "/dev/stdin" ] || [ "$0" = "sh" ] ; then
        return
    fi
883
    local F="$0"
Vitaly Lipatov's avatar
Vitaly Lipatov committed
884 885 886
    if [ -n "$2" ] ; then
        is_dirpath "$2" && F="$2" || F="$(dirname $0)/$2"
    fi
887

888
    cat "$F" | grep -- "# $1" | while read -r n ; do
Vitaly Lipatov's avatar
Vitaly Lipatov committed
889 890 891 892 893 894
        if echo "$n" | grep -q "# $1: PART: " ; then
            echo
            echo "$n" | sed -e "s|# $1: PART: ||"
            continue
        fi
        echo "$n" | grep -q "^ *#" && continue
895 896 897
        opt=`echo $n | sed -e "s|) # $1:.*||g" -e 's|"||g' -e 's@^|@@'`
        desc=`echo $n | sed -e "s|.*) # $1:||g"`
        printf "    %-20s %s\n" "$opt" "$desc"
898 899 900
    done
}

901
set_bigtmpdir()
902
{
903 904 905 906
    # TODO: improve BIGTMPDIR conception
    # https://bugzilla.mozilla.org/show_bug.cgi?id=69938
    # https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch05s15.html
    # https://geekpeach.net/ru/%D0%BA%D0%B0%D0%BA-systemd-tmpfiles-%D0%BE%D1%87%D0%B8%D1%89%D0%B0%D0%B5%D1%82-tmp-%D0%B8%D0%BB%D0%B8-var-tmp-%D0%B7%D0%B0%D0%BC%D0%B5%D0%BD%D0%B0-tmpwatch-%D0%B2-centos-rhel-7
907 908 909 910
    if [ -z "$BIGTMPDIR" ] ; then
        BIGTMPDIR="/var/tmp"
        [ -d "$BIGTMPDIR" ] || BIGTMPDIR="$TMPDIR"
    fi
911 912 913 914 915 916 917
    export BIGTMPDIR
}

assure_tmpdir()
{
    if [ -z "$TMPDIR" ] ; then
        export TMPDIR="/tmp"
918
        debug "Your have no TMPDIR defined. Using $TMPDIR as fallback."
919 920
    fi

921 922 923 924
    if [ ! -d "$TMPDIR" ] ; then
        fatal "TMPDIR $TMPDIR does not exist."
    fi

925 926 927 928 929
    if [ ! -w "$TMPDIR" ] ; then
        fatal "TMPDIR $TMPDIR is not writable."
    fi
}

930 931 932 933 934 935 936 937
test_shell()
{
    local R
    R="$($CMDSHELL /dev/null 2>&1)"
    [ -n "$R" ] && fatal "$CMDSHELL is broken (bash wrongly printing out '$R'). Check ~/.bashrc and /etc/bashrc, run $CMDSHELL manually for test."
}


938 939
set_distro_info()
{
940 941 942

    test_shell

943 944
    # TODO: return when we will not ask run under root
    #[ -n "$SUDO_USER" ] && warning "It is not necessary to run epm using sudo."
945

946 947 948 949 950 951 952 953 954 955 956 957
    assure_tmpdir

    set_bigtmpdir

    # don't run again in subprocesses
    [ -n "$DISTRVENDOR" ] && return 0

    DISTRVENDOR=$PROGDIR/distr_info

    # export pack of variables, see epm print info --print-eepm-env
    [ -n "$verbose" ] && $DISTRVENDOR --print-eepm-env
    eval $($DISTRVENDOR --print-eepm-env | grep -v '^ *#')
958 959 960 961 962
}

# FIXME: detect if not recognized
set_pm_type()
{
963 964
    local CMD
    set_distro_info
965

966
# override package manager detection result
967 968 969 970 971
if [ -n "$EPM_BACKEND" ] ; then
    PMTYPE=$EPM_BACKEND
    return
fi
# obsoleted
972
if [ -n "$FORCEPM" ] ; then
973 974
    PMTYPE=$FORCEPM
    return
975 976
fi

977
}
978

979 980
is_active_systemd()
{
981
    [ "$DISTRCONTROL" = "systemd" ]
982
}
983 984 985

assure_distr()
{
986 987 988
    local TEXT="this option"
    [ -n "$2" ] && TEXT="$2"
    [ "$DISTRNAME" = "$1" ] || fatal "$TEXT supported only for $1 distro"
989
}
990 991 992 993 994

# return delimiter sign in depend of package type
get_pkg_name_delimiter()
{
   local pkgtype="$1"
995
   [ -n "$pkgtype" ] || pkgtype="$PKGFORMAT"
996 997 998 999

   [ "$pkgtype" = "deb" ] && echo "_" && return
   echo "-"
}
1000

1001
# used via remove_on_exit
1002 1003
__epm_remove_tmp_files()
{
1004
    trap "-" EXIT
1005 1006
    [ -n "$DEBUG" ] && return 0

1007 1008
    [ -n "$verbose" ] && info "Removing tmp files on exit ..."

1009 1010
    if [ -n "$to_clean_tmp_dirs" ] ; then
        echo "$to_clean_tmp_dirs" | while read p ; do
1011 1012
            [ -n "$verbose" ] && echo "rm -rf '$p'"
            rm -rf "$p" 2>/dev/null
1013 1014 1015 1016 1017
        done
    fi

    if [ -n "$to_clean_tmp_files" ] ; then
        echo "$to_clean_tmp_files" | while read p ; do
1018
            rm $verbose -f "$p" 2>/dev/null
1019
        done
1020
    fi
1021

1022 1023 1024 1025
    return 0
}


1026 1027
remove_on_exit()
{
1028 1029 1030 1031
    if [ -z "$set_remove_on_exit" ] ; then
        trap "__epm_remove_tmp_files" EXIT
        set_remove_on_exit=1
    fi
1032 1033
    while [ -n "$1" ] ; do
        if [ -d "$1" ] ; then
1034 1035
            to_clean_tmp_dirs="$to_clean_tmp_dirs
$1"
1036
        elif [ -f "$1" ] ; then
1037 1038
            to_clean_tmp_files="$to_clean_tmp_files
$1"
1039 1040 1041 1042 1043
        fi
        shift
    done
}

1044 1045 1046 1047 1048
#has_space()
#{
#    estrlist -- has_space "$@"
#}
# use internal implementation for speed
1049 1050
has_space()
{
1051 1052 1053
        # not for dash:
        [ "$1" != "${1/ //}" ]
        # [ "$(echo "$*" | sed -e "s| ||")" != "$*" ]
1054
}
1055

1056

1057 1058
is_url()
{
1059
    echo "$1" | grep -q "^[filehtps]*:/"
1060 1061
}

1062
# print a path to the command if exists in $PATH
1063
if a= type -a type 2>/dev/null >/dev/null ; then
1064 1065
print_command_path()
{
1066
    a= type -fpP -- "$1" 2>/dev/null
1067
}
1068 1069 1070
elif a= which which 2>/dev/null >/dev/null ; then
    # the best case if we have which command (other ways needs checking)
    # TODO: don't use which at all, it is a binary, not builtin shell command
1071 1072
print_command_path()
{
1073
    a= which -- "$1" 2>/dev/null
1074 1075 1076 1077
}
else
print_command_path()
{
1078
    a= type "$1" 2>/dev/null | sed -e 's|.* /|/|'
1079 1080 1081 1082 1083 1084 1085 1086 1087
}
fi

# check if <arg> is a real command
is_command()
{
    print_command_path "$1" >/dev/null
}

1088
# compatibility layer
1089

1090
# add realpath if missed (with -s support)
1091
if ! is_command realpath ; then
1092 1093 1094
realpath()
{
    [ -n "$*" ] || return
1095 1096 1097 1098 1099
    if [ "$1" = "-s" ] ; then
        shift
        echo "$(cd "$(dirname "$1")" && pwd -P)/$(basename "$1")" #"
        return
    fi
1100 1101 1102 1103
    readlink -f "$@"
}
fi

1104

1105 1106 1107 1108 1109
# TODO: use perl if sed -i is not accessible
# sed -i is only supported in GNU sed.
#  sed -i "s/$find/$replace/g" "$@"
#  perl -p -i -e "s/$find/$replace/g" "$@"

1110
# add subst if missed
1111
if ! is_command subst ; then
1112 1113 1114 1115 1116
subst()
{
    sed -i -e "$@"
}
fi
1117 1118 1119

check_core_commands()
{
1120 1121 1122
    #which which >/dev/null || fatal "Can't find which command (which or debianutils package is missed?)"
    is_command grep || fatal "Can't find grep command (coreutils package is missed?)"
    is_command sed || fatal "Can't find sed command (sed package is missed?)"
1123 1124
}

1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137
export TEXTDOMAIN=eepm
if [ "$EPMMODE" = "git" ] ; then
    TEXTDOMAINDIR=$PROGDIR/../po
else
    TEXTDOMAINDIR='/usr/share/locale'
fi
export TEXTDOMAINDIR

if [ -d "$TEXTDOMAINDIR" ] && is_command gettext.sh ; then
	. gettext.sh
else
	eval_gettext()
	{
1138
		eval "echo -n \"$@\""
1139 1140
	}
fi