#!/bin/sh # This file is a part of Julia. License is MIT: https://julialang.org/license # build-time mini version of WinRPM, usage: # ./winrpm.sh http://download.opensuse.org/repositories/windows:/mingw:/win64/openSUSE_13.2/ mingw64-zlib1 # depends on curl, xmllint, gunzip, sort -V, sha256sum, and p7zip set -e url=$1 toinstall=$2 for i in curl xmllint gunzip sort sha256sum 7z; do if [ -z "$(which $i 2>/dev/null)" ]; then echo "error: this script requires having $i installed" >&2 exit 1 fi done # there is a curl --retry flag but it wasn't working here for some reason retry_curl() { for i in $(seq 10); do curl -fLsS $1 && return #sleep 2 done echo "error: failed to download $1" >&2 exit 1 } xp="xmllint --xpath" # the local-name() complication here is due to xml namespaces loc="local-name()=" eval $(retry_curl $url/repodata/repomd.xml | $xp "/*[$loc'repomd'] \ /*[$loc'data'][@type='primary']/*[$loc'location']/@href" -) case $href in *.gz) primary=$(retry_curl $url/$href | gunzip);; *) primary=$(retry_curl $url/$href);; esac # outputs xml string for newest version # don't include arch=src packages, those will list build-time dependencies rpm_select() { candidates="$(echo $primary | $xp "//*[$loc'package'] \ [./*[$loc'name' and .='$1']][./*[$loc'arch' and .='noarch']]" - \ 2>/dev/null | sed -e 's|" # remove rpm namespacing so output can be parsed by xmllint later if [ "$candidates" = "" ]; then echo "error: no package candidates found for $1" >&2 exit 1 fi epochs="" for i in $(echo $candidates | $xp "/c/package/version/@epoch" -); do eval $i epochs="$epochs $epoch" done maxepoch=$(echo $epochs | sed 's/ /\n/g' | sort -V -u | tail -n 1) vers="" for i in $(echo $candidates | $xp "/c/package/version \ [@epoch='$maxepoch']/@ver" -); do eval $i vers="$vers $ver" done maxver=$(echo $vers | sed 's/ /\n/g' | sort -V -u | tail -n 1) rels="" for i in $(echo $candidates | $xp "/c/package/version \ [@epoch='$maxepoch'][@ver='$maxver']/@rel" -); do eval $i rels="$rels $rel" done maxrel=$(echo $rels | sed 's/ /\n/g' | sort -V -u | tail -n 1) repeats=$(echo $rels | sed 's/ /\n/g' | sort -V | uniq -d | tail -n 1) if [ "$repeats" = "$maxrel" ]; then echo "warning: multiple candidates found for $1 with same version:" >&2 echo "epoch $maxepoch, ver $maxver, rel $maxrel, picking at random" >&2 fi echo $candidates | $xp "/c/package[version[@epoch='$maxepoch'] \ [@ver='$maxver'][@rel='$maxrel']][1]" - } for i in $toinstall; do # fail if no available candidates for requested packages if [ -z "$(rpm_select $i)" ]; then exit 1 fi done # outputs package and dll names, e.g. mingw64(zlib1.dll) rpm_requires() { for i in $(rpm_select $1 | \ $xp "/package/format/requires/entry/@name" - 2>/dev/null); do eval $i echo $name done } # outputs package name, warns if multiple providers with different names rpm_provides() { providers=$(echo $primary | $xp "//*[$loc'package'][./*[$loc'format'] \ /*[$loc'provides']/*[$loc'entry'][@name='$1']]/*[$loc'name']" - | \ sed -e 's|||g' -e 's||\n|g' | sort -u) if [ $(echo $providers | wc -w) -gt 1 ]; then echo "warning: found multiple providers $providers for $1, adding all" >&2 fi echo $providers } newpkgs=$toinstall allrequires="" while [ -n "$newpkgs" ]; do newrequires="" for i in $newpkgs; do for j in $(rpm_requires $i); do # leading and trailing spaces to ensure word match case " $allrequires $newrequires " in *" $j "*) # already on list ;; *) newrequires="$newrequires $j";; esac done done allrequires="$allrequires $newrequires" newpkgs="" for i in $newrequires; do provides="$(rpm_provides $i)" case " $toinstall $newpkgs " in *" $provides "*) # already on list ;; *) newpkgs="$newpkgs $provides";; esac done toinstall="$toinstall $newpkgs" done mkdir -p noarch for i in $toinstall; do pkgi=$(rpm_select $i) checksum=$(echo $pkgi | $xp "/package/checksum/text()" -) eval $(echo $pkgi | $xp "/package/location/@href" -) echo "downloading $href" $(dirname "$0")/../../deps/tools/jldownload $href $url/$href echo "$checksum *$href" | sha256sum -c 7z x -y $href cpiofile=$(basename $href | sed 's/.rpm$/.cpio/') rm $href 7z x -y $cpiofile rm $cpiofile done rmdir --ignore-fail-on-non-empty noarch