#!/bin/sh # # Copyright by The HDF Group. # All rights reserved. # # This file is part of HDF5. The full HDF5 copyright notice, including # terms governing use, modification, and redistribution, is contained in # the LICENSE file, which can be found at the root of the source code # distribution tree, or in https://www.hdfgroup.org/licenses. # If you do not have access to either file, you may request a copy from # help@hdfgroup.org. # # Make a release of hdf5. # Function definitions # # Function to get version from H5public.h get_version() { local major=$(grep '^#define H5_VERS_MAJOR' src/H5public.h | awk '{print $3}') local minor=$(grep '^#define H5_VERS_MINOR' src/H5public.h | awk '{print $3}') local release=$(grep '^#define H5_VERS_RELEASE' src/H5public.h | awk '{print $3}') local subrelease=$(grep '^#define H5_VERS_SUBRELEASE' src/H5public.h | cut -d'"' -f2) echo "${major}.${minor}.${release}${subrelease}" } # Function to set version in H5public.h # Usage: set_version "2.0.1-of20250116" set_version() { if [ $# -ne 1 ]; then echo "usage: set_version " return 1 fi new_vers=$1 # Validate version string format if ! echo "$new_vers" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9._-]+)?$'; then echo "Error: Invalid version format '$new_vers'. Expected format: major.minor.release[-subrelease]" return 1 fi # Parse version string (format: major.minor.release or major.minor.release-subrelease) major=$(echo $new_vers | sed 's/^\([0-9]*\)\..*/\1/') minor=$(echo $new_vers | sed 's/^[0-9]*\.\([0-9]*\)\..*/\1/') release=$(echo $new_vers | sed 's/^[0-9]*\.[0-9]*\.\([0-9]*\).*/\1/') # Note: subrelease includes the leading dash (e.g., "-snap0") to match H5_VERS_STR concatenation subrelease=$(echo $new_vers | sed 's/^[0-9]*\.[0-9]*\.[0-9]*\(.*\)/\1/') # If subrelease is same as new_vers, there was no subrelease part if [ "$subrelease" = "$new_vers" ]; then subrelease="" fi # Validate that all components were extracted if [ -z "$major" ] || [ -z "$minor" ] || [ -z "$release" ]; then echo "Error: Failed to parse version components from '$new_vers'" echo " major=$major, minor=$minor, release=$release, subrelease=$subrelease" return 1 fi # Verify H5public.h exists and has the expected defines if [ ! -f src/H5public.h ]; then echo "Error: src/H5public.h not found" return 1 fi for def in H5_VERS_MAJOR H5_VERS_MINOR H5_VERS_RELEASE H5_VERS_SUBRELEASE; do if ! grep -q "^#define $def" src/H5public.h; then echo "Error: #define $def not found in src/H5public.h" return 1 fi done # Update H5public.h # Note: H5_VERS_STR and H5_VERS_INFO are automatically derived from the base version macros sed -i.bak \ -e "s/^\(#define H5_VERS_MAJOR[[:space:]]*\)[0-9]*/\1$major/" \ -e "s/^\(#define H5_VERS_MINOR[[:space:]]*\)[0-9]*/\1$minor/" \ -e "s/^\(#define H5_VERS_RELEASE[[:space:]]*\)[0-9]*/\1$release/" \ -e "s/^\(#define H5_VERS_SUBRELEASE[[:space:]]*\)\".*\"/\1\"$subrelease\"/" \ src/H5public.h if [ $? -ne 0 ]; then echo "Error: sed command failed" mv src/H5public.h.bak src/H5public.h 2>/dev/null return 1 fi # Verify the changes were applied correctly new_major=$(grep '^#define H5_VERS_MAJOR' src/H5public.h | sed 's/^#define H5_VERS_MAJOR[[:space:]]*\([0-9]*\).*/\1/') new_minor=$(grep '^#define H5_VERS_MINOR' src/H5public.h | sed 's/^#define H5_VERS_MINOR[[:space:]]*\([0-9]*\).*/\1/') new_release=$(grep '^#define H5_VERS_RELEASE' src/H5public.h | sed 's/^#define H5_VERS_RELEASE[[:space:]]*\([0-9]*\).*/\1/') new_subrelease=$(grep '^#define H5_VERS_SUBRELEASE' src/H5public.h | sed 's/^#define H5_VERS_SUBRELEASE[[:space:]]*"\(.*\)".*/\1/') if [ "$new_major" != "$major" ] || [ "$new_minor" != "$minor" ] || \ [ "$new_release" != "$release" ] || [ "$new_subrelease" != "$subrelease" ]; then echo "Error: Version update verification failed" echo " Expected: major=$major, minor=$minor, release=$release, subrelease=$subrelease" echo " Got: major=$new_major, minor=$new_minor, release=$new_release, subrelease=$new_subrelease" mv src/H5public.h.bak src/H5public.h return 1 fi # Success - remove backup rm -f src/H5public.h.bak echo "Successfully updated version to $new_vers" return 0 } # Print Usage page USAGE() { cat << EOF Usage: $0 -d [-h] [--private] [--revision [--branch BRANCHNAME]] ... -d DIR The name of the directory where the release(s) should be placed. --branch BRANCHNAME This is to get the correct version of the branch name from the repository. BRANCHNAME for v1.8 should be hdf5_1_8. -h print the help page. --private Make a private release with today's date in version information. --revision Make a private release with the code revision number in version information. This must be run at the top level of the source directory. The other command-line options are the names of the programs to use for compressing the resulting tar archive (if none are given then "tar" is assumed): tar -- use tar and don't do any compressing. gzip -- use gzip with "-9" and append ".gz" to the output name. bzip2 -- use bzip2 with "-9" and append ".bz2" to the output name. zip -- convert all text files to DOS style and form a zip file for Windows use. doc -- produce the latest doc tree in addition to the archive. A sha256 checksum is produced for each archive created and stored in a corresponding sha256 file. Examples: $ bin/release -d /tmp /tmp/hdf5-1.8.13-RELEASE.txt /tmp/hdf5-1.8.13.tar /tmp/hdf5-1.8.13.tar.sha256 $ bin/release -d /tmp gzip /tmp/hdf5-1.8.13-RELEASE.txt /tmp/hdf5-1.8.13.tar /tmp/hdf5-1.8.13.tar.sha256 /tmp/hdf5-1.8.13.tar.gz /tmp/hdf5-1.8.13.tar.gz.sha256 $ bin/release -d /tmp tar gzip zip /tmp/hdf5-1.8.13-RELEASE.txt /tmp/hdf5-1.8.13.tar /tmp/hdf5-1.8.13.tar.sha256 /tmp/hdf5-1.8.13.tar.gz /tmp/hdf5-1.8.13.tar.gz.sha256 /tmp/hdf5-1.8.13.zip /tmp/hdf5-1.8.13.zip.sha256 Note: as of HDF5 2.0.0, RELEASE.txt is replaced by CHANGELOG.md The integrity of a downloaded file can be verified on Linux platforms by running "sha256sum --check .sha256, which will display 'OK' if the calculated checksum of matches the checksum in .sha256. EOF } # Function name: tar2zip # Convert the release tarball to a Windows zipball. # # Steps: # 1. untar the tarball in a temporary directory; # Note: do this in a temporary directory to avoid changing # the original source directory which may be around. # 2. convert all its text files to DOS (LF-CR) style; # 3. form a zip file which is usable by Windows users. # # Parameters: # $1 version # $2 release tarball # $3 output zipball file name # # Returns 0 if successful; 1 otherwise # tar2zip() { if [ $# -ne 3 ]; then echo "usage: tar2zip " return 1 fi ztmpdir=/tmp/ztmpdir$$ mkdir -p $ztmpdir version=$1 tarfile=$2 zipfile=$3 # step 1: untar tarball in ztmpdir (cd $ztmpdir; tar xf -) < $tarfile # sanity check if [ ! -d $ztmpdir/$version ]; then echo "untar did not create $ztmpdir/$version source dir" # cleanup rm -rf $ztmpdir return 1 fi # step 2: convert text files # There maybe a simpler way to do this. # options used in unix2dos: # -k Keep the date stamp # -q quiet mode # grep redirect output to /dev/null because -q or -s are not portable. find $ztmpdir/$version | \ while read inf; do \ if file $inf | grep "$inf\: .*text" > /dev/null 2>&1 ; then \ unix2dos -q -k $inf; \ fi\ done # step 3: make zipball # -9 maximum compression # -y Store symbolic links as such in the zip archive # -r recursive # -q quiet (cd $ztmpdir; zip -9 -y -r -q $version.zip $version) mv $ztmpdir/$version.zip $zipfile # cleanup rm -rf $ztmpdir } # Defaults DEST=releases VERS=$(get_version) VERS_OLD= test "$VERS" || exit 1 verbose=yes release_date=`date +%F` today=`date +%Y%m%d` pmode='no' revmode='no' tmpdir="../#release_tmp.$$" # tmp work directory # Restore previous Version information RESTORE_VERSION() { if [ X-${VERS_OLD} != X- ]; then echo restoring version information back to $VERS_OLD rm -f config/lt_vers.am cp $tmpdir/lt_vers.am config/lt_vers.am set_version $VERS_OLD VERS_OLD= fi } # Command-line arguments while [ -n "$1" ]; do arg=$1 shift case "$arg" in -d) DEST=$1 shift ;; -h) USAGE exit 0 ;; --private) pmode=yes ;; --revision) revmode=yes ;; --branch) BRANCHNAME=$1 shift ;; -*) echo "Unknown switch: $arg" 1>&2 USAGE exit 1 ;; *) methods="$methods $arg" ;; esac done # Default method is tar if [ "X$methods" = "X" ]; then methods="tar" fi # Create the temporary work directory. if mkdir $tmpdir; then echo "temporary work directory for release. "\ "Can be deleted after release completes." > $tmpdir/README else echo "Failed to mkdir tmpdir($tmpdir)" exit 1 fi # setup restoration in case of abort. trap RESTORE_VERSION 0 if [ X$pmode = Xyes ]; then VERS_OLD=$VERS # Copy old version of config/lt_vers.am, since it's hard to # "undo" changes to it. cp config/lt_vers.am $tmpdir # Set version information to m.n.r-of$today. VERS=`echo $VERS | sed -e s/-.*//`-of$today echo Private release of $VERS set_version $VERS fi if [ X$revmode = Xyes ]; then VERS_OLD=$VERS echo "Save old version $VERS_OLD for restoration later." # Copy old version of config/lt_vers.am, since it's hard to # "undo" changes to it. cp config/lt_vers.am $tmpdir if [ "${BRANCHNAME}" = "" ]; then BRANCHNAME=`git symbolic-ref -q --short HEAD` fi revision=`git rev-parse --short HEAD` # Set version information to m.n.r-r$revision. VERS=`echo $VERS | sed -e s/-.*//`-$revision echo Private release of $VERS HDF5_VERS=hdf5-$BRANCHNAME-$revision echo file base of $HDF5_VERS set_version $VERS # use a generic directory name for revision releases HDF5_IN_VERS=hdfsrc else # Store hdf5-$VERS ("hdf5-1.7.51", e.g.) to a variable to avoid typos HDF5_VERS=hdf5-$VERS # directory name matches tar file name for non-revision releases HDF5_IN_VERS=$HDF5_VERS fi test "$verbose" && echo "Releasing $HDF5_VERS to $DEST" 1>&2 if [ ! -d $DEST ]; then echo " Destination directory $DEST does not exist" 1>&2 exit 1 fi # Create a symlink to the source so files in the tarball have the prefix # we want (gnu's --transform isn't portable) ln -s `pwd` $tmpdir/$HDF5_IN_VERS || exit 1 # Update README.md and release_docs/CHANGELOG.md with release information in # line 1. for f in README.md release_docs/CHANGELOG.md; do echo "HDF5 version $VERS released on $release_date" >$f.x sed -e 1d $f >>$f.x mv $f.x $f # Make sure new files are of the right access mode chmod 644 $f done # Create the tar file test "$verbose" && echo " Running tar..." 1>&2 (cd "$tmpdir" && exec tar -ch --exclude-vcs --exclude=.clang-format --exclude=.codespellrc --exclude=.devcontainer --exclude=.git* --exclude=.h5chkright.ini -f "$HDF5_VERS.tar" "./$HDF5_IN_VERS" || exit 1 ) # Compress #SHA256=$HDF5_VERS.sha256 cp /dev/null $DEST/$SHA256 for comp in $methods; do case $comp in tar) cp -p $tmpdir/$HDF5_VERS.tar $DEST/$HDF5_VERS.tar (cd $DEST; sha256sum $HDF5_VERS.tar > $HDF5_VERS.tar.sha256) ;; gzip) test "$verbose" && echo " Running gzip..." 1>&2 gzip -9 <$tmpdir/$HDF5_VERS.tar >$DEST/$HDF5_VERS.tar.gz (cd $DEST; sha256sum $HDF5_VERS.tar.gz > $HDF5_VERS.tar.gz.sha256) ;; bzip2) test "$verbose" && echo " Running bzip2..." 1>&2 bzip2 -9 <$tmpdir/$HDF5_VERS.tar >$DEST/$HDF5_VERS.tar.bz2 (cd $DEST; sha256sum $HDF5_VERS.tar.bz2 > $HDF5_VERS.tar.bz2.sha256) ;; zip) test "$verbose" && echo " Creating zip ball..." 1>&2 tar2zip $HDF5_IN_VERS $tmpdir/$HDF5_VERS.tar $DEST/$HDF5_VERS.zip 1>&2 (cd $DEST; sha256sum $HDF5_VERS.zip > $HDF5_VERS.zip.sha256) ;; *) echo "***Error*** Unknown method $comp" exit 1 ;; esac done # Copy CHANGELOG.mc to the release area cp release_docs/CHANGELOG.md $DEST/$HDF5_VERS-CHANGELOG.md # Restore OLD version information, then no need for trap. if [ X$pmode = Xyes ] || [ X$revmode = Xyes ]; then echo "Restore the original version $VERS_OLD" RESTORE_VERSION trap 0 fi # Remove temporary things rm -rf $tmpdir echo "DONE" exit 0