#!/bin/sh # This script uses the SciJava Maven repository at https://maven.scijava.org/ # to fetch an artifact, or to determine the state of it. # error out whenever a command fails set -e root_url () { test snapshots != "$2" || { if curl -fs https://maven.scijava.org/service/local/repositories/sonatype-snapshots/content/"$1"/maven-metadata.xml > /dev/null 2>&1 then echo https://maven.scijava.org/service/local/repositories/sonatype-snapshots/content else echo https://maven.scijava.org/content/repositories/snapshots fi return } echo https://maven.scijava.org/service/local/repo_groups/public/content } die () { echo "$*" >&2 exit 1 } # Helper (thanks, BSD!) get_mtime () { stat -c %Y "$1" } case "$(uname -s 2> /dev/null)" in MINGW*) get_mtime () { date -r "$1" +%s } ;; Darwin) get_mtime () { stat -f %m "$1" } ;; esac # Parse <groupId>:<artifactId>:<version> triplets (i.e. GAV parameters) groupId () { echo "${1%%:*}" } artifactId () { result="${1#*:}" echo "${result%%:*}" } version () { result="${1#*:}" case "$result" in *:*) echo "${1##*:}" ;; esac } # Given an xml, extract the first <tag> extract_tag () { result="${2%%</$1>*}" case "$result" in "$2") ;; *) echo "${result#*<$1>}" ;; esac } # Given an xml, extract the last <tag> extract_last_tag () { result="${2##*<$1>}" case "$result" in "$2") ;; *) echo "${result%%</$1>*}" ;; esac } # Given an xml, skip all <tag> sections skip_tag () { result="$2" while true do case "$result" in *"<$1>"*) result="${result%%<$1>*}${result#*</$1>}" ;; *) break ;; esac done echo "$result" } # Given the xml of a POM, find the parent GAV parent_gav_from_pom_xml () { pom="$1" parent="$(extract_tag parent "$pom")" test -n "$parent" || return groupId="$(extract_tag groupId "$parent")" artifactId="$(extract_tag artifactId "$parent")" version="$(extract_tag version "$parent")" echo "$groupId:$artifactId:$version" } # Given a GAV parameter, determine the base URL of the project project_url () { gav="$1" artifactId="$(artifactId "$gav")" infix="$(groupId "$gav" | tr . /)/$artifactId" version="$(version "$gav")" case "$version" in *SNAPSHOT) echo "$(root_url $infix snapshots)/$infix" ;; *) # Release could be in either releases or thirdparty; try releases first project_url="$(root_url $infix releases)/$infix" header=$(curl -Is "$project_url/") case "$header" in HTTP/1.?" 200 OK"*) ;; *) project_url="$(root_url $infix thirdparty)/$infix" ;; esac echo "$project_url" ;; esac } # Given a GAV parameter, determine the URL of the .jar file jar_url () { gav="$1" artifactId="$(artifactId "$gav")" version="$(version "$gav")" infix="$(groupId "$gav" | tr . /)/$artifactId/$version" case "$version" in *-SNAPSHOT) url="$(root_url $infix snapshots)/$infix/maven-metadata.xml" metadata="$(curl -s "$url")" timestamp="$(extract_tag timestamp "$metadata")" buildNumber="$(extract_tag buildNumber "$metadata")" version=${version%-SNAPSHOT}-$timestamp-$buildNumber echo "$(root_url $infix snapshots)/$infix/$artifactId-$version.jar" ;; *) echo "$(root_url $infix releases)/$infix/$artifactId-$version.jar" ;; esac } # Given a GAV parameter, return the URL to the corresponding .pom file pom_url () { url="$(jar_url "$1")" echo "${url%.jar}.pom" } # Given a POM file, find its GAV parameter gav_from_pom () { pom="$(cat "$1")" parent="$(extract_tag parent "$pom")" pom="$(skip_tag parent "$pom")" pom="$(skip_tag dependencies "$pom")" pom="$(skip_tag profiles "$pom")" pom="$(skip_tag build "$pom")" groupId="$(extract_tag groupId "$pom")" test -n "$groupId" || groupId="$(extract_tag groupId "$parent")" artifactId="$(extract_tag artifactId "$pom")" version="$(extract_tag version "$pom")" test -n "$version" || version="$(extract_tag version "$parent")" echo "$groupId:$artifactId:$version" } # Given a GAV parameter, find its parent's GAV parent_gav () { gav="$1" groupId="$(groupId "$gav")" artifactId="$(artifactId "$gav")" version="$(version "$gav")" test -n "$version" || version="$(latest_version "$gav")" pom="$(read_pom "$groupId:$artifactId:$version")" parent_gav_from_pom_xml "$pom" } # Given a POM file, find its parent's GAV parent_gav_from_pom () { pom="$(cat "$1")" parent_gav_from_pom_xml "$pom" } # Given a POM file, extract its packaging packaging_from_pom () { pom="$(cat "$1")" pom="$(skip_tag parent "$pom")" pom="$(skip_tag dependencies "$pom")" pom="$(skip_tag profiles "$pom")" pom="$(skip_tag build "$pom")" packaging="$(extract_tag packaging "$pom")" echo "${packaging:-jar}" } # Given a GAV parameter possibly lacking a version, determine the latest version latest_version () { metadata="$(curl -s "$(project_url "$1")"/maven-metadata.xml)" latest="$(extract_tag release "$metadata")" test -n "$latest" || latest="$(extract_tag latest "$metadata")" test -n "$latest" || latest="$(extract_last_tag version "$metadata")" echo "$latest" } # Given a GA parameter, invalidate the cache in SciJava's Nexus' group/public SONATYPE_DATA_CACHE_URL=https://maven.scijava.org/service/local/data_cache/repositories/sonatype/content SONATYPE_SNAPSHOTS_DATA_CACHE_URL=https://maven.scijava.org/service/local/data_cache/repositories/sonatype-snapshots/content invalidate_cache () { ga="$1" artifactId="$(artifactId "$ga")" infix="$(groupId "$ga" | tr . /)/$artifactId" curl --netrc -i -X DELETE \ $SONATYPE_DATA_CACHE_URL/$infix/maven-metadata.xml && curl --netrc -i -X DELETE \ $SONATYPE_SNAPSHOTS_DATA_CACHE_URL/$infix/maven-metadata.xml && version="$(latest_version "$ga")" && infix="$infix/$version" && curl --netrc -i -X DELETE \ $SONATYPE_DATA_CACHE_URL/$infix/$artifactId-$version.pom && if test "$artifactId" = "${artifactId#pom-}" then curl --netrc -i -X DELETE \ $SONATYPE_DATA_CACHE_URL/$infix/$artifactId-$version.jar fi } # Generate a temporary file; not thread-safe tmpfile () { i=1 while test -f /tmp/precompiled.$i"$1" do i=$(($i+1)) done echo /tmp/precompiled.$i"$1" } # Given a GAV or a path, read the POM read_pom () { case "$1" in pom.xml|*/pom.xml|*\\pom.xml) cat "$1" ;; *) curl -s "$(pom_url "$1")" ;; esac } # Given a GAV parameter (or pom.xml path) and a name, resolve a property (falling back to parents) get_property () { gav="$1" key="$2" case "$key" in imagej1.version) latest_version net.imagej:ij return ;; project.groupId) groupId "$gav" return ;; project.version) version "$gav" return ;; esac while test -n "$gav" do pom="$(read_pom "$gav")" properties="$(extract_tag properties "$pom")" property="$(extract_tag "$key" "$properties")" if test -n "$property" then echo "$property" return fi gav="$(parent_gav_from_pom_xml "$pom")" done die "Could not resolve \${$2} in $1" } # Given a GAV parameter and a string, expand properties expand () { gav="$1" string="$2" result= while true do case "$string" in *'${'*'}'*) result="$result${string%%\$\{*}" string="${string#*\$\{}" key="${string%\}*}" result="$result$(get_property "$gav" "$key")" string="${string#$key\}}" ;; *) echo "$result$string" break ;; esac done } # Given a GAV parameter, make a list of its dependencies (as GAV parameters) get_dependencies () { pom="$(read_pom "$1")" while true do case "$pom" in *'<dependency>'*) dependency="$(extract_tag dependency "$pom")" scope="$(extract_tag scope "$dependency")" case "$scope" in ''|compile) groupId="$(expand "$1" "$(extract_tag groupId "$dependency")")" artifactId="$(extract_tag artifactId "$dependency")" version="$(expand "$1" "$(extract_tag version "$dependency")")" echo "$groupId:$artifactId:$version" ;; esac pom="${pom#*</dependency>}" ;; *) break; esac done } # Given a GAV parameter and a space-delimited list of GAV parameters, expand # the list by the first parameter and its dependencies (unless the list already # contains said parameter) get_all_dependencies () { case " $2 " in *" $1 "*) ;; # list already contains the depdendency *) gav="$1" set "" "$2 $1" for dependency in $(get_dependencies "$gav") do set "" "$(get_all_dependencies "$dependency" "$2")" done ;; esac echo "$2" } # Given a GAV parameter, download the .jar file get_jar () { url="$(jar_url "$1")" tmpfile="$(tmpfile .jar)" curl -s "$url" > "$tmpfile" test "<html" != "$(head -c 5 "$tmpfile")" || curl -s "${url%.jar}.nar" > "$tmpfile" test PK = "$(head -c 2 "$tmpfile")" echo "$tmpfile" } # Given a GAV parameter, get the commit from the manifest of the deployed .jar commit_from_gav () { jar="$(get_jar "$1")" unzip -p "$jar" META-INF/MANIFEST.MF | sed -n -e 's/^Implementation-Build: *//pi' | tr -d '\r' rm "$jar" } # Given a GAV parameter, determine whether the .jar file is already in plugins/ # or jars/ is_jar_installed () { artifactId="$(artifactId "$1")" version="$(version "$1")" file=$artifactId-$version.jar test -f "$file" || file=../plugins/$file test -f "$file" || return 1 case "$version" in *-SNAPSHOT) # is the file younger than a day? mtime="$(get_mtime "$file")" test "$(($mtime-$(date +%s)))" -gt -86400 ;; esac } # Given a .jar file, determine whether it is an ImageJ 1.x plugin is_ij1_plugin () { unzip -l "$1" plugins.config > /dev/null 2>&1 } # Given a GAV parameter, download the .jar file and its dependencies as needed # and install them into plugins/ or jars/, respectively install_jar () { for gav in $(get_all_dependencies "$1") do if ! is_jar_installed "$gav" then tmp="$(get_jar "$gav")" name="$(artifactId "$gav")-$(version "$gav").jar" if test -d ../plugins && is_ij1_plugin "$tmp" then mv "$tmp" "../plugins/$name" else mv "$tmp" "$name" fi fi done } # Determine whether a local project (specified as pom.xml) needs to be deployed is_deployed () { gav="$(gav_from_pom "$1")" && commit="$(commit_from_gav "$gav")" && test -n "$commit" && dir="$(dirname "$1")" && (cd "$dir" && git diff --quiet "$commit".. -- .) } # The main part case "$1" in commit) commit_from_gav "$2" ;; deps|dependencies) get_dependencies "$2" ;; all-deps|all-dependencies) get_all_dependencies "$2" | tr ' ' '\n' | grep -v '^$' ;; latest-version) latest_version "$2" ;; invalidate-cache) invalidate_cache "$2" ;; gav-from-pom) gav_from_pom "$2" ;; parent-gav) parent_gav "$2" ;; pom-url) pom_url "$2" ;; parent-gav-from-pom) parent_gav_from_pom "$2" ;; packaging-from-pom) packaging_from_pom "$2" ;; property-from-pom|get-property|property) if test $# -lt 3 then get_property pom.xml "$2" else get_property "$2" "$3" fi ;; install) install_jar "$2" ;; is-deployed) is_deployed "$2" ;; *) test $# -eq 0 || echo "Unknown command: $1" >&2 die "Usage: $0 [command] [argument...]"' Commands: commit <groupId>:<artifactId>:<version> Gets the commit from which the given artifact was built. dependencies <groupId>:<artifactId>:<version> Lists the direct dependencies of the given artifact. all-dependencies <groupId>:<artifactId>:<version> Lists all dependencies of the given artifact, including itself and transitive dependencies. latest-version <groupId>:<artifactId>[:<version>] Prints the current version of the given artifact (if "SNAPSHOT" is passed as version, it prints the current snapshot version rather than the release one). invalidate-cache <groupId>:<artifactId> Invalidates the version cached in the SciJava Nexus from OSS Sonatype, e.g. after releasing a new version to Sonatype. Requires appropriate credentials in $HOME/.netrc for https://maven.scijava.org/. parent-gav <groupId>:<artifactId>[:<version>] Prints the GAV parameter of the parent project of the given artifact. pom-url <groupId>:<artifactId>:<version> Gets the URL of the POM describing the given artifact. gav-from-pom <pom.xml> Prints the GAV parameter described in the given pom.xml file. parent-gav-from-pom <pom.xml> Prints the GAV parameter of the parent project of the pom.xml file. packaging-from-pom <pom.xml> Prints the packaging type of the given project. property-from-pom <pom.xml> <property-name> Prints the property specified in the pom.xml file (or in its parents). install <groupId>:<artifactId>:<version> Installs the given artifact and all its dependencies; if the artifact or dependency to install is an ImageJ 1.x plugin and the parent directory contains a subdirectory called "plugins", it will be installed there, otherwise into the current directory. is-deployed <pom.xml> Tests whether the specified project is deployed alright. Fails with exit code 1 if not. ' ;; esac