epm-restore 11.4 KB
Newer Older
1 2
#!/bin/sh
#
3 4
# Copyright (C) 2020, 2021  Etersoft
# Copyright (C) 2020, 2021  Vitaly Lipatov <lav@etersoft.ru>
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
#
# 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
# (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
# GNU Affero General Public License for more details.
#
# 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/>.
#

load_helper epm-sh-altlinux
load_helper epm-assure

23 24 25 26 27 28
# file prefix suffix
__epm_restore_print_comment()
{
    echo "#$2 generated by 'epm restore --dry-run' from $(basename $(dirname $(realpath "$1")))/$(basename "$1")$3"
}

29
# FIXME: python modules are packaged into python packages, but we have only module names and rpm package names instead of python packages
30 31
# enable python3dest(PEP-503 normalized name) provides
# https://bugzilla.altlinux.org/show_bug.cgi?id=39003
32 33
__epm_filter_pip_to_rpm()
{
34
    tr "A-Z" "a-z" | sed -e "s|_|-|g" -e "s|^python[-_]||" \
35
        -e "s|bs4|beautifulsoup4|" \
36
        -e "s|pillow|Pillow|" \
37 38
        -e "s|sqlalchemy|SQLAlchemy|" \
        -e "s|flask-SQLAlchemy|flask_sqlalchemy|" \
39
        -e "s|redis|redis-py|" \
40
        -e "s|pyjwt|jwt|" \
41
        -e "s|pymonetdb|monetdb|" \
42
        -e "s|pyyaml|yaml|" \
43
        -e "s|flask-migrate|Flask-Migrate|" \
44 45
        -e "s|twisted|twisted-core|" \
        -e "s|pymacaroons|pymacaroons-pynacl|" \
46
        -e "s|pygments|Pygments|" \
47 48 49 50
        -e "s|memcached|memcache|" \
        -e "s|pyopenssl|OpenSSL|"
}

51 52 53 54
# TODO: remove me
fill_sign()
{
    local sign="$1"
55
    echo "$2" | grep -E -- "$sign[[:space:]]*[0-9.]+?" | sed -E -e "s|.*$sign[[:space:]]*([0-9.]+?).*|\1|"
56 57 58
}


59 60 61
# macro pkg caseline
__epm_pi_sign_to_rpm()
{
62 63 64 65
    local t="$1"
    local l="$2"
    local equal="$3"
    [ -n "$equal" ] || equal=">="
66 67 68

    local pi=''
    local sign ll
69
    for sign in "<=" "<" ">=" ">" "==" "!=" "~="; do
70 71 72
        ll=$(fill_sign "$sign" "$l")
        [ -n "$ll" ] || continue
        [ "$sign" = "==" ] && sign="$equal"
73
        [ "$sign" = "~=" ] && sign="$equal"
74 75 76
        [ "$sign" = "!=" ] && sign=">="
        [ -n "$pi" ] && pi="$pi
"
77
        pi="$pi$t $sign $ll"
78
    done
79
    [ -n "$pi" ] || pi="$t"
80 81 82
    echo "$pi"
}

83
__epm_get_array_name()
84
{
85 86
    echo "$*" | grep "=" | head -n1 | sed -e 's| *=.*||'
}
87

88 89 90 91 92
__epm_lineprint_python_array()
{
    local a="$*"
    [ -n "$a" ] || return
    local name="$(__epm_get_array_name "$a")"
93
    (echo "$a" | sed -E -e 's@(\]|\)).*@\1@' ; echo "print('\n'.join($name))" ) | ( a= python3 - || a= python - )
94 95 96 97 98 99 100 101
}

# translate pip requirement lines to rpm notation
# (compare signs and package names)
__epm_restore_convert_to_rpm_notation()
{
    local equal="$1"
    local l
102
    while read l ; do
103
        if echo "$l" | grep -q "; *python_version *< *['\"]3" ; then
104 105 106 107 108
            [ -n "$verbose" ] && warning "    $t is python2 only requirement, skipped"
            continue
        fi
        # drop various "python_version > '3.5'"
        l="$(echo "$l" | sed -e "s| *;.*||")"
109
        if echo "$l" | grep -qE "^ *#" || [ -z "$l" ] ; then
110 111
            continue
        fi
112
        local t="$(echo "$l" | sed -E -e "s|[[:space:]]*[<>!=~]+.*||" -e "s| *#.*||" | __epm_filter_pip_to_rpm)"
113
        [ -n "$t" ] || continue
114 115 116 117 118
        # until new section
        if echo "$l" | grep -qE "^\[" ; then
            break
        fi
        # if dependency_links URLs, use egg name
119 120 121 122
        if echo "$l" | grep -qE "://" ; then
            if echo "$l" | grep -q "#egg=" ; then
                t="$(echo "$l" | sed -e "s|.*#egg=||" -e "s|\[.*||" | __epm_filter_pip_to_rpm)"
            else
123
                warning "    skipping URL $l ..."
124 125 126
                continue
            fi
        fi
127

128 129 130 131 132 133 134 135 136
        __epm_pi_sign_to_rpm "$t" "$l" "$equal"
    done
}

__epm_restore_pip()
{
    local req_file="$1"
    local reqmacro
    local ilist
137

138
    if [ -n "$dryrun" ] ; then
139
        reqmacro="%py3_use"
140
        basename "$req_file" | egrep -q "(dev|test)" && reqmacro="%py3_buildrequires"
141
        echo
142
        __epm_restore_print_comment "$req_file"
143
        cat $req_file | __epm_restore_convert_to_rpm_notation | sed -e "s|^|$reqmacro |"
144
        return
145 146 147
    else
        info "Install requirements from $req_file ..."
        ilist="$(cat $req_file | __epm_restore_convert_to_rpm_notation | cut -d' ' -f 1 | sed -e "s|^|python3-module-|")"
148 149
    fi

150
    ilist="$(estrlist list $ilist)"
151 152 153
    docmd epm install $ilist
}

154 155
__eresection()
{
156
    rhas "$1" "[[:space:]]*$2[[:space:]]*=[[:space:]]*[\[(]"
157 158
}

159 160 161 162 163 164 165
__epm_restore_setup_py()
{
    local req_file="$1"
    if [ -z "$dryrun" ] ; then
        info "Install requirements from $req_file ..."
    fi

166
    local ar=''
167 168
    local ilist=''
    local reqmacro
169
    local section=''
170 171 172 173
    while read l ; do
        if rhas "$l" "^ *#" ; then
            continue
        fi
174 175 176 177
        # start of section
        if __eresection "$l" "REQUIREMENTS" ; then
            reqmacro="%py3_use"
            section="$l"
178
        fi
179
        if __eresection "$l" "install_requires" ; then
180
            reqmacro="%py3_use"
181
            section="$l"
182
        fi
183
        if __eresection "$l" "setup_requires" ; then
184
            reqmacro="%py3_buildrequires"
185 186 187 188 189 190 191 192 193 194 195 196
            section="$l"
        fi
        if __eresection "$l" "tests_require" ; then
            reqmacro="%py3_buildrequires"
            section="$l"
        fi
        if [ -n "$section" ] ; then
            ar="$ar
$l"
        fi

        # not end of section
197
        if [ -z "$section" ] || ! rhas "$l" "(\]|\)),*" ; then
198 199
            continue
        fi
200 201 202

        if [ -n "$dryrun" ] ; then
            echo
203
            __epm_restore_print_comment "$req_file" "" " $(__epm_get_array_name "$section")"
204 205 206 207 208 209
            __epm_lineprint_python_array "$ar" | __epm_restore_convert_to_rpm_notation ">=" | sed -e "s|^|$reqmacro |"
        else
            ilist="$ilist $(__epm_lineprint_python_array "$ar" | __epm_restore_convert_to_rpm_notation ">=" | cut -d' ' -f 1 | sed -e "s|^|python3-module-|")"
        fi
        section=''
        ar=''
210 211 212 213 214
    done < $req_file

    if [ -n "$dryrun" ] ; then
        return
    fi
215

216
    ilist="$(estrlist list $ilist)"
217
    docmd epm install $ilist
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
__epm_print_npm_list()
{
    local reqmacro="$1"
    local req_file="$2"
    local l
    while read l ; do
        # "tap": "^14.10.7"
        echo "$l" | grep -q '"\(.*\)": "\(.*\)"' || continue
        local name="$(echo "$l" | sed -e 's|.*"\(.*\)": ".*|\1|')"
        [ -z "$name" ] && continue
        local ver="$(echo "$l" | sed -e 's|.*"\(.*\)": "\(.*\)".*|\2|')" #'
        [ -z "$name" ] && continue

        if [ -n "$dryrun" ] ; then
            local pi=''
            local sign
            if echo "$ver" | grep -q "^\^" ; then
                sign=">="
            else
                sign="="
            fi
            ll=$(echo "$ver" | sed -e 's|^[^~]||')
            pi="$pi$reqmacro node-$name $sign $ll"
#         [ -n "$pi" ] && pi="$pi
#"
#           [ -n "$pi" ] || pi="$pi$reqmacro: node-$t"
            echo "$pi"
            continue
        else
            local pi="node-$name"
            #echo "    $l -> $name -> $pi"
        fi
        [ -n "$name" ] || continue
        ilist="$ilist $pi"
    done < $req_file

    [ -n "$dryrun" ] || echo "$ilist"
}

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

__epm_print_nupkg_list()
{
    a= dotnet list $1 package | grep "^   > " | while read n name req other; do
        if [ -n "$dryrun" ] ; then
            echo "BuildRequires: nupkg($name) >= $req"
        else
            echo "nupkg($name)"
        fi
    done
}

__epm_restore_nupkg()
{
    local req_file="$1"
    if [ -n "$dryrun" ] ; then
        echo "# generated via dotnet list $(basename $(dirname $(realpath "$req_file")))/$(basename "$req_file") package"
        __epm_print_nupkg_list $req_file
        return
    fi

    info "Install requirements from $req_file ..."
    ilist=$(__epm_print_nupkg_list $req_file)
    ilist="$(estrlist list $ilist)"
    docmd epm install $ilist
}

286 287 288 289 290 291 292 293 294 295
__epm_restore_npm()
{
    local req_file="$1"

    epm assure jq

    if [ -n "$dryrun" ] ; then
        local lt=$(mktemp)
        a= jq .dependencies <$req_file >$lt
        echo
296
        __epm_restore_print_comment "$req_file"
297 298 299
        __epm_print_npm_list "Requires:" $lt

        echo
300
        __epm_restore_print_comment "$req_file" " devDependencies"
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
        a= jq .devDependencies <$req_file >$lt
        __epm_print_npm_list "BuildRequires:" $lt
        rm -f $lt
        return
    fi

    info "Install requirements from $req_file ..."
    local lt=$(mktemp)
    a= jq .dependencies <$req_file >$lt
    ilist="$(__epm_print_npm_list "" $lt)"
    a= jq .devDependencies <$req_file >$lt
    ilist="$ilist $(__epm_print_npm_list "" $lt)"
    rm -f $lt
    docmd epm install $ilist
}

317 318 319 320
__epm_restore_by()
{
    local req_file="$1"
    [ -s "$req_file" ] || return
321 322 323 324 325

    if file $req_file | grep -q "ELF [3264]*-bit LSB executable" ; then
        assure_exists ldd-requires
        showcmd ldd-requires $req_file
        local TOINSTALL="$(a= ldd-requires $req_file | grep "^apt-get install" | sed -e "s|^apt-get install ||")"
326 327 328 329
        if [ -n "$dryrun" ] ; then
            estrlist list $TOINSTALL
            return
        fi
330
        [ -n "$TOINSTALL" ] || { info "There are no missed packages is found for $req_file binary." ; return ; }
331
        docmd epm install $TOINSTALL
332 333 334
        return
    fi

335 336 337 338 339 340
    case $req_file in
        requirements/default.txt|requirements/dev.txt|requirements/test.txt)
            [ -s "$req_file" ] && __epm_restore_pip "$req_file" && return
            ;;
    esac

341
    case $(basename $req_file) in
342
        requirements.txt|dev-requirements.txt|requirements-dev.txt|requirements_dev.txt|requirements_test.txt|requirements-test.txt|test-requirements.txt|requires.txt)
343 344
            [ -s "$req_file" ] && __epm_restore_pip "$req_file"
            ;;
345
        setup.py|python_dependencies.py)
346 347
            [ -s "$req_file" ] && __epm_restore_setup_py "$req_file"
            ;;
348 349 350
        package.json)
            [ -s "$req_file" ] && __epm_restore_npm "$req_file"
            ;;
351 352 353 354
        *.sln|*.csproj)
            local PROJ="$(echo $req_file)"
            [ -s "$PROJ" ] && __epm_restore_nupkg "$PROJ"
            ;;
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
        Gemfile|package.json)
            info "$req_file support is not implemented yet"
            ;;
    esac
}

epm_restore()
{
    req_file="$pkg_filenames"
    if [ -n "$pkg_urls" ] && echo "$pkg_urls" | grep -qE "^https?://" ; then
        req_file="$(basename "$pkg_urls")"
        #assure eget
        [ -r "$req_file" ] && fatal "File $req_file is already exists in $(pwd)"
        info "Downloading '$req_file' from '$pkg_urls' ..."
        eget "$pkg_urls"
        [ -s "$req_file" ] || fatal "Can't download $req_file from '$pkg_urls'"
    fi

    if [ -n "$req_file" ] ; then
        __epm_restore_by $req_file
        return
    fi

378 379
# TODO: nowhere works: python3 setup.py --requires

380
    # if run with empty args
381 382 383 384
    for i in requirements.txt requirements/default.txt requirements_dev.txt requirements-dev.txt requirements/dev.txt dev-requirements.txt \
             requirements-test.txt requirements_test.txt  requirements/test.txt test-requirements.txt \
             Gemfile requires.txt package.json setup.py python_dependencies.py \
             *.sln *.csproj ; do
385 386 387 388
        __epm_restore_by $i
    done

}