1#!/usr/bin/env bash 2 3die() { 4 printf %s "${*+$'\e[31merror: \e[0m'$*$'\n'}" 5 (( usage )) && usage 6 exit 1 7} >&2 8 9usage() { 10 cat <<-EOF 11 Usage: $0 [options] [uri://to/source-tarball] category/port 12 13 Creates a recipe template for a crates.io package, filled with 14 information at hand. Requires awk, coreutils, sed, tar (with the 15 appropriate decompression utility), and wget. 16 17 Options: 18 -h, --help show this help message and exit 19 -k, --keep keep the generated temporary directory 20 -nc, --no-clobber 21 do not overwrite existing files 22 -psd, --print-source-directories 23 also print SOURCE_DIRs 24 -b, --bump 25 bump the crates.io dependencies of the port's highest 26 versioned recipe instead (overrides --no-clobber) 27 -c CMD, --cmd=CMD 28 specify the command runtime 29 EOF 30} 31 32temp() { rm -rf "$tempdir"; } 33 34. "$(finddir B_USER_SETTINGS_DIRECTORY)"/haikuports.conf 35(( $# )) || usage=1 die 36while (( $# )); do 37 case $1 in 38 -h|--help) 39 usage 40 exit 0 41 ;; 42 -k|--keep) 43 temp() { printf '%s\n' "Kept $tempdir"; } 44 ;; 45 -nc|--no-clobber) 46 nc=1 47 shopt -s expand_aliases 48 alias mv='mv -n' 49 alias cp='cp -n' 50 ;; 51 -psd|--print-source-directories) 52 psd=3 53 ;; 54 -b|--bump) 55 bump=1 56 ;; 57 -c) 58 shift 59 ;& 60 --cmd=*) 61 cmd=${1#*=} 62 ;; 63 *://*) 64 SOURCE_URI=$1 65 ;; 66 *-*/*) 67 directory=$TREE_PATH/$1 68 : "${1//-/_}" 69 portName=${_#*/} 70 ;; 71 -?*) 72 usage=1 die "Invalid option." 73 ;; 74 *) 75 usage=1 die "Invalid argument." 76 ;; 77 esac 78 shift 79done 80 81mkdir -p "$directory"/download 82cd "$directory" || die "Invalid port directory." 83 84if (( bump )); then 85 eval "recipe=$( 86 ls -v --quoting-style=shell-escape \ 87 "$portName"-[0-9]*.[0-9]*.[0-9]*.recipe | tail -n 1 88 )" 89 90 portVersionedName=${recipe%.recipe} 91 portVersion=${portVersionedName#$portName-} 92 93 defineDebugInfoPackage() { :; } 94 getPackagePrefix() { :; } 95 96 . "$recipe" || die "Sourcing the recipe file failed." 97fi 98 99: "${cmd:=$portName}" "${psd:=2}" "${SOURCE_URI%/}" 100source_file=${_##*/} 101: "${SOURCE_FILENAME:=$source_file}" 102 103case "" in 104 $directory) 105 usage=1 die "No category and/or port specified." 106 ;;& 107 $SOURCE_URI) 108 usage=1 die "SOURCE_URI is empty or unset." 109 ;;& 110 $CHECKSUM_SHA256) 111 if [[ nc -eq 0 || ! -e download/$SOURCE_FILENAME ]]; then 112 wget -O download/"$SOURCE_FILENAME" "$SOURCE_URI" || 113 die "Failed to download the source file." 114 fi 115 CHECKSUM_SHA256=1 116 ;; 117esac 118 119if [[ $CHECKSUM_SHA256 != 1 ]]; then 120 for (( i = 0; i < 3; ++i )); do 121 printf '%s\n' "$CHECKSUM_SHA256 download/$SOURCE_FILENAME" | 122 sha256sum -c && break 123 (( i < 2 )) && wget -O download/"$SOURCE_FILENAME" \ 124 "$( (( i < 1 )) && printf -- "-c")" "$SOURCE_URI" 125 done || die "Checksum verification failed." 126else 127 : "$(sha256sum download/"$SOURCE_FILENAME")" 128 CHECKSUM_SHA256=${_::64} 129fi 130 131: "$(tar --exclude=*/* -tf download/"$SOURCE_FILENAME")" 132SOURCE_DIR=${_%/} 133if test "$SOURCE_FILENAME" != "$SOURCE_DIR.tar.${source_file##*.}"; then 134 mv download/{"$SOURCE_FILENAME","$_"} 135 SOURCE_FILENAME=${_##*/} 136fi 137 138tempdir=$(mktemp -d -t "$SOURCE_DIR".XXXXXX) 139trap temp 0 140tar --transform "s|$SOURCE_DIR|${tempdir##*/}|" -C /tmp \ 141 -xf download/"$SOURCE_FILENAME" --wildcards "$SOURCE_DIR/Cargo.*" || 142 die "Failed to extract the necessary files." 143 144info=$( 145 if grep -q '\[metadata\]' "$tempdir"/Cargo.lock; then 146 sed -e '0,/\[metadata\]/d 147 s/checksum // 148 s/(.*)// 149 s/ /-/ 150 s/ = // 151 s/"//g' "$tempdir"/Cargo.lock 152 else 153 awk -F \" ' 154 /name|version|checksum/ { 155 if ($1 ~ "name") 156 i += 1 157 data[i] = data[i] "," $2 158 } 159 160 END { 161 for (j in data) { 162 split(data[j], f, ",") 163 if (length(f[4]) == 64) 164 print f[2] " " f[3] " " f[4] 165 } 166 }' "$tempdir"/Cargo.lock | sort | sed 's/ /-/' 167 fi 168) 169 170mapfile -t crates < <(awk '{ print $1".crate" }' <<< "$info") 171mapfile -t checksums < <(awk '{ print $2 }' <<< "$info") 172echo "$info" 173for crate in "${crates[@]}"; do 174 uris+=("https://static.crates.io/crates/${crate%%-[0-9]*.[0-9]*.[0-9]*}/$crate") 175 (( psd == 3 )) && dirs+=("${crate%.crate}") 176done 177 178for (( i = 0; j = i+2, i < ${#crates[@]}; i++ )); do 179 source_uris+=("SOURCE_URI_$j=\"${uris[i]}\"") 180 checksums_sha256+=("CHECKSUM_SHA256_$j=\"${checksums[i]}\"") 181 merged+=("${source_uris[i]}" "${checksums_sha256[i]}") 182 (( psd == 3 )) && { 183 source_dirs+=("SOURCE_DIR_$j=\"${dirs[i]}\"") 184 merged+=("${source_dirs[i]}") 185 } 186done 187 188if (( bump )); then 189 sed -i \ 190 -e '/SOURCE_URI_2/,/ARCHITECTURES/ { /^A/!d }' \ 191 -e "/^ARCHITECTURES/i $(printf '%s\n' "${merged[@]}" | 192 sed '0~'"$psd"' a\\' | head -n -1 | 193 sed -z 's/\n/\\n/g')" \ 194 -e "s/{2\.\.[0-9]\+}/{2..$(( "${#crates[@]}" + 1 ))}/" \ 195 "$recipe" 196 exit 197fi 198 199eval "$( 200 sed -n '/\[package\]/,/^$/ { 201 /"""\|\[/d 202 s/-\(.*=\)/_\1/ 203 s/ = /=/p 204 }' "$tempdir"/Cargo.toml 205)" 206cat <<EOF >"$tempdir/$portName-$version.recipe" 207SUMMARY="${description%.}" 208DESCRIPTION="$( 209 extended=$( 210 grep -q extended-description "$tempdir"/Cargo.toml && 211 printf "extended-" 212 ) 213 214 sed -n "/${extended}description"' = """/,/"""/ { 215 s/.*description = // 216 s/"""//g 217 /^$/d 218 p 219 }' "$tempdir"/Cargo.toml 220)" 221HOMEPAGE="$homepage" 222COPYRIGHT="" 223LICENSE="$( 224 IFS=$'\n' read -d "" -ra licenses <<< "$( 225 sed -e 's,/\| AND \| OR ,\n,g 226 s,-\([0-9]\)\.0, v\1,g' <<< "$license" | sort 227 )" 228 printf %s "${licenses[0]}" 229 (( ${#licenses[@]} > 1 )) && printf '\n\t%s' "${licenses[@]:1}" 230)" 231REVISION="1" 232SOURCE_URI="$( 233 : "${SOURCE_URI//$version/\$portVersion}" 234 printf '%s\n' "${_/$homepage/\$HOMEPAGE}" 235)" 236CHECKSUM_SHA256="$CHECKSUM_SHA256" 237$( 238 if [[ $source_file != "$SOURCE_FILENAME" ]]; then 239 : "${SOURCE_FILENAME/$version/\$portVersion}" 240 printf '%s\n' "SOURCE_FILENAME=\"$_\"" 241 fi 242 printf '\n' 243 printf '%s\n' "${merged[@]}" | sed '0~'"$psd"' a\\' 244) 245 246ARCHITECTURES="!x86_gcc2 ?x86 ?x86_64" 247commandBinDir=\$binDir 248if [ "\$targetArchitecture" = x86_gcc2 ]; then 249SECONDARY_ARCHITECTURES="?x86" 250commandBinDir=\$prefix/bin 251fi 252 253PROVIDES=" 254 $portName\$secondaryArchSuffix = \$portVersion 255 cmd:$cmd 256 " 257REQUIRES=" 258 haiku\$secondaryArchSuffix 259 " 260 261BUILD_REQUIRES=" 262 haiku\${secondaryArchSuffix}_devel 263 " 264BUILD_PREREQUIRES=" 265 cmd:cargo\$secondaryArchSuffix 266 cmd:gcc\$secondaryArchSuffix 267 " 268 269defineDebugInfoPackage $portName\$secondaryArchSuffix \\ 270 "\$commandBinDir"/$cmd 271 272BUILD() 273{ 274 export CARGO_HOME=\$sourceDir/../cargo 275 vendor=\$CARGO_HOME/haiku 276 mkdir -p "\$vendor" 277 for i in \$(seq 2 $(( ${#crates[@]} + 1 ))); do 278 eval "srcDir=\\\$sourceDir\$i" 279 eval "sha256sum=\\\$CHECKSUM_SHA256_\$i" 280 set -- "\$srcDir"$( 281 (( psd == 2 )) && printf "/*" 282 ) 283 ln -sf "\$1" "\$vendor" 284 cat <<-EOF >"\$vendor/\${1##*/}/.cargo-checksum.json" 285 { 286 "package": "\$sha256sum", 287 "files": {} 288 } 289 EOF 290 done 291 292 cat <<-EOF >"\$CARGO_HOME"/config 293 [source.haiku] 294 directory = "\$vendor" 295 296 [source.crates-io] 297 replace-with = "haiku" 298 EOF 299 300 cargo build --release --frozen 301} 302 303INSTALL() 304{ 305 install -m 755 -d "\$commandBinDir" "\$docDir" 306 install -m 755 target/release/$cmd "\$commandBinDir" 307 install -m 644 README.md "\$docDir" 308} 309 310TEST() 311{ 312 export CARGO_HOME=\$sourceDir/../cargo 313 cargo test --release --frozen 314} 315EOF 316cp "$tempdir/$portName-$version.recipe" . 317 318if [[ -v license_file ]]; then 319 cat <<-EOF 320 ----------------------------------------------------------------------- 321 This port uses a custom license file. 322 It will be installed to the port's license directory; please rename it 323 as appropriate and add it to the recipe. 324 EOF 325 tar --transform "s|$SOURCE_DIR|${tempdir##*/}|" -C /tmp \ 326 -xf download/"$SOURCE_FILENAME" "${license_file/#./$SOURCE_DIR}" 327 mkdir -p licenses 328 cp "$tempdir"/"$license_file" licenses 329fi 330