epm-restore 10.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
#!/bin/sh
#
# Copyright (C) 2020  Etersoft
# Copyright (C) 2020  Vitaly Lipatov <lav@etersoft.ru>
#
# 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
# FIXME: python modules are packaged into python packages, but we have only module names and rpm package names instead of python packages
24 25
# enable python3dest(PEP-503 normalized name) provides
# https://bugzilla.altlinux.org/show_bug.cgi?id=39003
26 27 28 29
__epm_filter_pip_to_rpm()
{
    tr "A-Z" "a-z" | sed -e "s|-|_|g" -e "s|^python_||" \
        -e "s|beautifulsoup4|bs4|" \
30
        -e "s|pillow|Pillow|" \
31
        -e "s|redis|redis-py|" \
32
        -e "s|pyjwt|jwt|" \
33
        -e "s|pytest_cov|pytest-cov|" \
34
        -e "s|pymonetdb|monetdb|" \
35
        -e "s|pyyaml|yaml|" \
36 37 38
        -e "s|twisted|twisted-core|" \
        -e "s|pymacaroons|pymacaroons-pynacl|" \
        -e "s|pyasn1_modules|pyasn1-modules|" \
39 40
        -e "s|pygments|Pygments|" \
        -e "s|patch_ng|patch-ng|" \
41 42 43 44
        -e "s|memcached|memcache|" \
        -e "s|pyopenssl|OpenSSL|"
}

45 46 47 48 49 50 51 52
# TODO: remove me
fill_sign()
{
    local sign="$1"
    echo "$2" | grep -E -- "$sign[[:space:]]*[0-9.]+?" | sed -E -- "s|.*$sign[[:space:]]*([0-9.]+?).*|\1|"
}


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

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

76
__epm_get_array_name()
77
{
78 79
    echo "$*" | grep "=" | head -n1 | sed -e 's| *=.*||'
}
80

81 82 83 84 85 86 87 88 89 90 91 92 93 94
__epm_lineprint_python_array()
{
    local a="$*"
    [ -n "$a" ] || return
    local name="$(__epm_get_array_name "$a")"
    (echo "$a" | sed -e 's|\].*|]|' ; echo "print('\n'.join($name))" ) | ( a= python - || a= python3 )
}

# translate pip requirement lines to rpm notation
# (compare signs and package names)
__epm_restore_convert_to_rpm_notation()
{
    local equal="$1"
    local l
95
    while read l ; do
96
        local t="$(echo "$l" | sed -e "s| *[<>!]*=.*||" -e "s| *#.*||" | __epm_filter_pip_to_rpm)"
97
        if echo "$l" | grep -qE "^ *#" || [ -z "$l" ] ; then
98 99
            continue
        fi
100
        [ -n "$t" ] || continue
101 102 103 104 105
        # until new section
        if echo "$l" | grep -qE "^\[" ; then
            break
        fi
        # if dependency_links URLs, use egg name
106 107 108 109
        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
110
                warning "    skipping URL $l ..."
111 112 113 114
                continue
            fi
        fi
        if echo "$l" | grep -q "; *python_version *< *'3.0'" ; then
115
            warning "    $t is python2 only requirement, skipped"
116 117
            continue
        fi
118 119 120 121 122 123 124 125 126
        __epm_pi_sign_to_rpm "$t" "$l" "$equal"
    done
}

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

128
    if [ -n "$dryrun" ] ; then
129
        reqmacro="%py3_use"
130
        basename "$req_file" | egrep -q "(dev|test)" && reqmacro="%py3_buildrequires"
131 132 133
        echo
        echo "# generated by epm --restore --dry-run from $(basename $(dirname $(realpath $req_file)))/$req_file"
        cat $req_file | __epm_restore_convert_to_rpm_notation | sed -e "s|^|$reqmacro |"
134
        return
135 136 137
    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-|")"
138 139
    fi

140
    ilist="$(estrlist list $ilist)"
141 142 143
    docmd epm install $ilist
}

144 145 146 147 148
__eresection()
{
    rhas "$1" "[[:space:]]*$2[[:space:]]*=[[:space:]]*\["
}

149 150 151 152 153 154 155
__epm_restore_setup_py()
{
    local req_file="$1"
    if [ -z "$dryrun" ] ; then
        info "Install requirements from $req_file ..."
    fi

156
    local ar=''
157 158
    local ilist=''
    local reqmacro
159
    local section=''
160 161 162 163
    while read l ; do
        if rhas "$l" "^ *#" ; then
            continue
        fi
164 165 166 167
        # start of section
        if __eresection "$l" "REQUIREMENTS" ; then
            reqmacro="%py3_use"
            section="$l"
168
        fi
169
        if __eresection "$l" "install_requires" ; then
170
            reqmacro="%py3_use"
171
            section="$l"
172
        fi
173
        if __eresection "$l" "setup_requires" ; then
174
            reqmacro="%py3_buildrequires"
175 176 177 178 179 180 181 182 183 184 185 186 187
            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
        if [ -z "$section" ] || ! rhas "$l" "\],*" ; then
188 189
            continue
        fi
190 191 192 193 194 195 196 197 198 199

        if [ -n "$dryrun" ] ; then
            echo
            echo "# generated by epm --restore --dry-run from $(basename $(dirname $(realpath $req_file)))/$req_file $(__epm_get_array_name "$section")"
            __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=''
200 201 202 203 204
    done < $req_file

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

206
    ilist="$(estrlist list $ilist)"
207
    docmd epm install $ilist
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
__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"
}

__epm_restore_npm()
{
    local req_file="$1"

    epm assure jq

    if [ -n "$dryrun" ] ; then
        local lt=$(mktemp)
        a= jq .dependencies <$req_file >$lt
        echo
        echo "# generated by epm --restore --dry-run from $(basename $(dirname $(realpath $req_file)))/$req_file"
        __epm_print_npm_list "Requires:" $lt

        echo
        echo "# devDependencies generated by epm --restore --dry-run from $(basename $(dirname $(realpath $req_file)))/$req_file"
        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
}

280 281 282 283
__epm_restore_by()
{
    local req_file="$1"
    [ -s "$req_file" ] || return
284 285 286 287 288

    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 ||")"
289 290 291 292
        if [ -n "$dryrun" ] ; then
            estrlist list $TOINSTALL
            return
        fi
293
        [ -n "$TOINSTALL" ] || { info "There are no missed packages is found for $req_file binary." ; return ; }
294
        docmd epm install $TOINSTALL
295 296 297
        return
    fi

298
    case $(basename $req_file) in
299
        requirements.txt|dev-requirements.txt|requirements-dev.txt|requirements_dev.txt|requirements_test.txt|requirements-test.txt|test-requirements.txt|requires.txt)
300 301
            [ -s "$req_file" ] && __epm_restore_pip "$req_file"
            ;;
302
        setup.py|python_dependencies.py)
303 304
            [ -s "$req_file" ] && __epm_restore_setup_py "$req_file"
            ;;
305 306 307
        package.json)
            [ -s "$req_file" ] && __epm_restore_npm "$req_file"
            ;;
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
        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

331 332
# TODO: nowhere works: python3 setup.py --requires

333
    # if run with empty args
334
    for i in requirements.txt requirements_dev.txt requirements-dev.txt dev-requirements.txt requirements-test.txt requirements_test.txt test-requirements.txt Gemfile requires.txt package.json setup.py python_dependencies.py; do
335 336 337 338
        __epm_restore_by $i
    done

}