aboutsummaryrefslogtreecommitdiff
path: root/lib/cpt.in
blob: 995fa5eca9422f83d42f08a9a98bdb06aa61a415 (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
#!/bin/sh -ef
# shellcheck source=/dev/null

log() {
    # Print a message prettily.
    #
    # All messages are printed to stderr to allow the user to hide build
    # output which is the only thing printed to stdout.
    #
    # '${3:-->}':         If the 3rd argument is missing, set prefix to '->'.
    # '${2:+colorb}':     If the 2nd argument exists, set text style of '$1'.
    printf '%b%s %b%b%s%b %s\n' \
           "$colory" "${3:-->}" "$colre" "${2:+$colorb}" "$1" "$colre" "$2" >&2
}

version() {
    log "Carbs Packaging Tools" @VERSION@
    exit 0
}

trap_set() {
    # Function to set the trap value.
    case ${1:-cleanup} in
        cleanup) trap pkg_clean EXIT INT ;;
        block)   trap '' INT ;;
        unset)   trap - EXIT INT ;;
    esac
}

_readlinkf() {
    # Public domain POSIX sh readlink function by Koichi Nakashima
    [ "${1:-}" ] || return 1
    max_symlinks=40
    CDPATH='' # to avoid changing to an unexpected directory

    target=$1
    [ -e "${target%/}" ] || target=${1%"${1##*[!/]}"} # trim trailing slashes
    [ -d "${target:-/}" ] && target="$target/"

    cd -P . 2>/dev/null || return 1
    while [ "$max_symlinks" -ge 0 ] && max_symlinks=$((max_symlinks - 1)); do
        if [ ! "$target" = "${target%/*}" ]; then
            case $target in
                /*) cd -P "${target%/*}/" 2>/dev/null || break ;;
                *) cd -P "./${target%/*}" 2>/dev/null || break ;;
            esac
            target=${target##*/}
        fi

        if [ ! -L "$target" ]; then
            target="${PWD%/}${target:+/}${target}"
            printf '%s\n' "${target:-/}"
            return 0
        fi

        # `ls -dl` format: "%s %u %s %s %u %s %s -> %s\n",
        #   <file mode>, <number of links>, <owner name>, <group name>,
        #   <size>, <date and time>, <pathname of link>, <contents of link>
        # https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html
        link=$(ls -dl -- "$target" 2>/dev/null) || break
        target=${link#*" $target -> "}
    done
    return 1
}

# CPT Library does "lazy loading" of its functions. Meaning that functions are
# defined, but the libraries containing the functions aren't loaded until one of
# those functions are called. This should theoretically decrease the time it
# takes to execute some script that uses only minimal amount of library
# functions. When a function listed below is called, its definition is replaced
# by the one in the loaded library, and executed with the same arguments.
# @AUTOLOADS@

# main()
{
    set -ef

    # Set the library directory if unset, assuming that it shares the same
    # prefix with the tool.
    [ "$CPT_LIBDIR" ] || CPT_LIBDIR=$(_readlinkf "$(command -v cpt-lib)") CPT_LIBDIR=${CPT_LIBDIR%/*}

    # If a parser definition exists, let's run it ourselves. This makes sure we
    # get the variables as soon as possible.
    command -v parser_definition >/dev/null && {
        eval "$(getoptions parser_definition parse "$0")"
        parse "$@"
        eval set -- "$REST"
    }

    # Create the cache directories for CPT and set the variables which point
    # to them. This is seperate from temporary directories created in
    # create_cache(). That's because we need these variables set on most
    # occasions.
    mkdir -p "${cac_dir:=${CPT_CACHE:=${XDG_CACHE_HOME:-$HOME/.cache}/cpt}}" \
             "${src_dir:=$cac_dir/sources}" \
             "${log_dir:=$cac_dir/logs}" \
             "${bin_dir:=$cac_dir/bin}"

    # Set the location to the repository and package database.
    pkg_db=var/db/cpt/installed

    # The PID of the current shell process is used to isolate directories
    # to each specific CPT instance. This allows multiple package manager
    # instances to be run at once. Store the value in another variable so
    # that it doesn't change beneath us.
    pid=${CPT_PID:-$$}

    # Force the C locale to speed up things like 'grep' which disable unicode
    # etc when this is set. We don't need unicode and a speed up is always
    # welcome.
    export LC_ALL=C LANG=C

    # Catch errors and ensure that build files and directories are cleaned
    # up before we die. This occurs on 'Ctrl+C' as well as success and error.
    trap_set cleanup

    # Prefer GNU grep if installed as it is much much faster than busybox's
    # implementation. Very much worth it if you value performance over
    # POSIX correctness (grep quoted to avoid shellcheck false-positive).
    grep=$(command -v ggrep) || grep='grep'

    # Prefer libarchive tar or GNU tar if installed as they are  much
    # much faster than busybox's implementation. Very much worth it if
    # you value performance.
    tar=$(command -v bsdtar || command -v gtar) || tar=tar

    # Figure out which 'sudo' command to use based on the user's choice or
    # what is available on the system.
    su=${CPT_SU:-$(command -v sls    ||
                   command -v sudo   ||
                   command -v doas)} || su=su

    # Store the date and time of script invocation to be used as the name
    # of the log files the package manager creates during builds.
    time=$(date '+%Y-%m-%d-%H:%M')

    # Use readelf for fixing dependencies if it is available, fallback to
    # ldd. readelf shows only the actual dependencies and doesn't include
    # the libraries required by the dependencies.
    elf_prog=${CPT_ELF:="$(
               command -v readelf       ||
               command -v llvm-readelf  ||
               command -v eu-readelf)"} || elf_prog=ldd

    # Make note of the user's current ID to do root checks later on.
    # This is used enough to warrant a place here.
    uid=$(id -u)

    # Save IFS, so we can restore it back to what it was before.
    old_ifs=$IFS

    # Make sure that the CPT_ROOT doesn't end with a '/'. This might
    # break some operations.
    CPT_ROOT=${CPT_ROOT%"${CPT_ROOT##*[!/]}"}

    # Define an optional sys_arch variable in order to provide
    # information to build files with architectural information.
    sys_arch=$(uname -m 2>/dev/null) ||:

    # Define this variable but don't create its directory structure from
    # the get go. It will be created as needed by package installation.
    sys_db=$CPT_ROOT/$pkg_db

    # This allows for automatic setup of a CPT chroot and will
    # do nothing on a normal system.
    mkdir -p "$CPT_ROOT/" 2>/dev/null ||:

    # Set a value for CPT_COMPRESS if it isn't set.
    : "${CPT_COMPRESS:=gz}"

    # Unless being piped or the user specifically doesn't want colors, set
    # colors. This can of course be overriden if the user specifically want
    # colors during piping.
    if { [ "$CPT_COLOR" != 0 ] && [ -t 1 ] ;} || [ "$CPT_COLOR" = 1 ]; then
        colory="\033[1;33m" colorb="\033[1;36m" colre="\033[m"
    fi

}