#!/bin/bash # # Copyright(c) 2020 Intel Corporation # SPDX-License-Identifier: BSD-3-Clause-Clear # # To make additional packages creation possible # through this script all you need to do is: # - add 'case' command to set variable 'GENERATE_=1' # - add function 'generate_' to handle the task # - add 'DEPENDENCIES_' array if needed # - update help! NAME="open-cas-linux" SUPPORTED_FROM_VERSION="20.3" THIS="$(basename $0)" ARCH="$(uname -i)" SCRIPT_BASE_DIR="$(dirname $(realpath $0))" BASE_SPEC="$SCRIPT_BASE_DIR/$NAME.spec.base" TEMP_TEMPLATE="opencas-${THIS}" DEPENDENCIES=(sed git) # Dependencies for particular packages creation: DEPENDENCIES_TAR=(tar) DEPENDENCIES_ZIP=(zip) DEPENDENCIES_RPM=(tar rpmbuild) DEPENDENCIES_SRPM=("${DEPENDENCIES_RPM[@]}") # List of relative submodule directories: SUBMODULES=( "ocf" "test/functional/test-framework" ) usage() { echo "Usage:" echo " ./$THIS [options] " echo " ./$THIS -c|-h" echo "where SOURCES_PATH is the root directory of OpenCAS sources" } print_help() { echo "Generate OpenCAS packages." echo "$(usage)" echo echo "This script generates various OpenCAS packages like release archives (tar, zip)," echo "RPMs (source and binary) as well as creates version file with metadata." echo echo "Mandatory arguments to long options are mandatory for short options too." echo echo "Commands:" echo " tar generate tar archive" echo " zip generate zip archive" echo " rpm generate RPM packages" echo " srpm generate SRPM package" echo " version-only create only version file and exit;" echo echo "Options:" echo " -o, --output-dir put all created files in the given directory;" echo " by default all files (except version file)" echo " will be put in 'SOURCES_PATH/packages/'" echo " -d, --debug create all debug files and packages as well" echo " -c, --clean clean all temporary files and folders that" echo " may have been left around if $THIS ended" echo " unexpectedly in the previous run" echo " -h, --help print this help message" echo } invalid_usage() { >&2 echo -e "$THIS: $*\nTry './$THIS --help' for more information." exit 2 } info() { echo -e "\e[33m$*\e[0m" } success() { echo -e "\n\e[32m=== ALL DONE ===\e[0m\n\nYou can find your fresh packages in '$OUTPUT_DIR'\n" } error() { >&2 echo -e "\e[31mERROR\e[0m: $THIS: $*" exit 1 } clean() { rm -rf "$TEMP_DIR" if [ -d "$TEMP_DIR" ]; then # Print only warning to not confuse the user by an error here # if packages were created successfully and everything else # went fine except cleaning temp directory at the end. info "WARNING: Cleanup failed" fi } clean_all() { info "Removing all temp files and dirs that may have been left around..." rm -rf /tmp/${TEMP_TEMPLATE}.* if [[ $(ls -A /tmp/${TEMP_TEMPLATE}.* 2>/dev/null) ]]; then # This function on the other hand is called only by a '-c' option # so we may throw an error here and exit. error "Cleanup failed" fi } check_options() { if [ ! "$SOURCES_DIR" ]; then invalid_usage "No mandatory SOURCES_PATH provided" elif [[ $(head -n 1 "$SOURCES_DIR/README.md" 2> /dev/null) != *Open*CAS*Linux* ]]; then invalid_usage "'$SOURCES_DIR' does not point to the root directory of CAS sources" elif [ ! "${!GENERATE_*}" ] && [ ! $VERSION_ONLY ]; then invalid_usage "Nothing to do - no command provided" fi } check_version() { cd "$TEMP_DIR" sh "$CAS_VERSION_GEN" > /dev/null if [ ! -f "$CAS_VERSION_GEN_FILE" ]; then error "Couldn't create CAS_VERSION file" fi while read -r line; do case "$line" in CAS_VERSION_MAIN*) CAS_VERSION_MAIN="${line##*=}";; CAS_VERSION_MAJOR*) CAS_VERSION_MAJOR="${line##*=}";; CAS_VERSION_MINOR*) CAS_VERSION_MINOR="${line##*=}";; esac done < "$CAS_VERSION_GEN_FILE" rm "$CAS_VERSION_GEN_FILE" cd - > /dev/null VERSION_SHORT="${CAS_VERSION_MAIN}.${CAS_VERSION_MAJOR}" if [ $CAS_VERSION_MINOR -ne 0 ]; then VERSION_SHORT+=".${CAS_VERSION_MINOR}" fi if [[ "$VERSION_SHORT" < "$SUPPORTED_FROM_VERSION" ]]; then echo "Sorry... this version of $NAME ($VERSION_SHORT) is not supported"\ "by $THIS. Use $NAME >= $SUPPORTED_FROM_VERSION" exit 1 fi for SUBMOD in ${SUBMODULES[@]}; do if [[ ! $(ls -A "$SOURCES_DIR/$SUBMOD") ]]; then local SUBMODULES_MISSING+="'$SUBMOD'\n" fi done if [ "$SUBMODULES_MISSING" ]; then error "There are missing submodules:\n${SUBMODULES_MISSING}\nUpdate submodules and try again!" fi if [ -d "$SOURCES_DIR/.git" ]; then CAS_VERSION_BUILD=$(printf %04d $(git -C "$SOURCES_DIR" log --merges --oneline | wc -l)) LAST_COMMIT_HASH=$(git -C "$SOURCES_DIR" log -1 --pretty=format:%H) LAST_COMMIT_HASH_ABBR=$(git -C "$SOURCES_DIR" log -1 --pretty=format:%h) LAST_COMMIT_DATE=$(git -C "$SOURCES_DIR" log -1 --pretty=format:%ci |\ sed "s/ /T/" | sed "s/ //" | sed "s/00$/:00/") LAST_COMMIT_TIMESTAMP=$(git -C "$SOURCES_DIR" log -1 --pretty=format:%ct) for SUBMOD in ${SUBMODULES[@]}; do LAST_SUB_COMMIT_HASHES+=($(git -C "$SOURCES_DIR/$SUBMOD" log -1 --pretty=format:%H)) LAST_SUB_COMMIT_HASHES_ABBR+=($(git -C "$SOURCES_DIR/$SUBMOD" log -1 --pretty=format:%h)) done elif [ -f "$VERSION_FILE" ]; then source "$VERSION_FILE" &> /dev/null else error "Couldn't obtain CAS version - no git tree nor version file within given sources" fi VERSION="${CAS_VERSION_MAIN}.${CAS_VERSION_MAJOR}.${CAS_VERSION_MINOR}.${CAS_VERSION_BUILD}" if [ $(git -C "$SOURCES_DIR" tag --points-at HEAD) ]; then RELEASE="release" elif [ $(git -C "$SOURCES_DIR" log -1 --pretty=format:%H)\ == $(git -C "$SOURCES_DIR" log -1 --merges --pretty=format:%H) ]; then RELEASE="master" else RELEASE="devel.${LAST_COMMIT_TIMESTAMP}" fi } check_dependencies() { echo "--- Checking for dependencies" for package in ${!GENERATE_*}; do local DEP_NAME="DEPENDENCIES_${package##*_}[@]" DEPENDENCIES+=(${!DEP_NAME}) done for DEP in ${DEPENDENCIES[@]}; do which $DEP &> /dev/null if [ $? -ne 0 ]; then local FAILED_DEPS+="$DEP " fi done if [ "$FAILED_DEPS" ]; then error "Dependencies not installed. You need to provide these programs first: $FAILED_DEPS" fi } create_dir() { mkdir -p "$*" if [ ! -d "$*" ] || [ ! -w "$*" ]; then error "No access to '$*'" fi } create_temp() { TEMP_DIR=$(mktemp -d -t ${TEMP_TEMPLATE}.XXXXXXXXXX) if [ $? -ne 0 ]; then error "Couldn't create temporary directory" fi } create_version_file() { echo "--- Creating version file" mkdir -p $(dirname "$VERSION_FILE") touch "$VERSION_FILE" if [ $? -ne 0 ]; then error "Couldn't create version file" fi CREATION_DATE=$(date --iso-8601=seconds) CREATION_TIMESTAMP=$(date +%s) echo "CREATION_DATE=$CREATION_DATE" > "$VERSION_FILE" echo "CREATION_TIMESTAMP=$CREATION_TIMESTAMP" >> "$VERSION_FILE" echo "CAS_VERSION_MAIN=$CAS_VERSION_MAIN" >> "$VERSION_FILE" echo "CAS_VERSION_MAJOR=$CAS_VERSION_MAJOR" >> "$VERSION_FILE" echo "CAS_VERSION_MINOR=$CAS_VERSION_MINOR" >> "$VERSION_FILE" echo "CAS_VERSION_BUILD=$CAS_VERSION_BUILD" >> "$VERSION_FILE" echo "LAST_COMMIT_HASH=$LAST_COMMIT_HASH" >> "$VERSION_FILE" echo "LAST_COMMIT_HASH_ABBR=$LAST_COMMIT_HASH_ABBR" >> "$VERSION_FILE" echo "LAST_COMMIT_DATE=$LAST_COMMIT_DATE" >> "$VERSION_FILE" echo "LAST_COMMIT_TIMESTAMP=$LAST_COMMIT_TIMESTAMP" >> "$VERSION_FILE" echo "LAST_SUB_COMMIT_HASHES=(${LAST_SUB_COMMIT_HASHES[@]})" >> "$VERSION_FILE" echo "LAST_SUB_COMMIT_HASHES_ABBR=(${LAST_SUB_COMMIT_HASHES_ABBR[@]})" >> "$VERSION_FILE" } archive_prepare() { if [ $ARCHIVE_PREPARED ]; then return 0 fi echo "--- Copying sources to the working directory" local TEMP_SOURCES_DIR="$TEMP_DIR/$CAS_FILENAME" rm -rf "$TEMP_SOURCES_DIR" mkdir -p "$TEMP_SOURCES_DIR" rsync -a --exclude="/packages" --exclude=".git*" --exclude=".pep8speaks.yml"\ "$SOURCES_DIR/" "$TEMP_SOURCES_DIR" ARCHIVE_PREPARED=1 } generate_tar() { if [ ! $TAR_CREATED ]; then archive_prepare echo "--- Creating tar archive from current sources" tar -C "$TEMP_DIR" -zcf "$TEMP_DIR/$SOURCES_TAR_NAME" "$CAS_FILENAME" if [ $? -ne 0 ] || [ ! -f "$TEMP_DIR/$SOURCES_TAR_NAME" ]; then rm -rf "$TEMP_DIR/$SOURCES_TAR_NAME" error "Couldn't create tar archive" fi TAR_CREATED=1 fi if [ "$1" != "temp" ]; then cp "$TEMP_DIR/$SOURCES_TAR_NAME" "$OUTPUT_DIR" fi } generate_zip() { archive_prepare echo "--- Creating zip archive from current sources" (cd "$TEMP_DIR" && zip -qr - "$CAS_FILENAME") > "$OUTPUT_DIR/$SOURCES_ZIP_NAME" if [ $? -ne 0 ] || [ ! -f "$OUTPUT_DIR/$SOURCES_ZIP_NAME" ]; then rm -rf "$OUTPUT_DIR/$SOURCES_ZIP_NAME" error "Couldn't create zip archive" fi } rpm_create_tree() { echo "--- Creating directory tree for building RPMs" mkdir -p "$RPM_BUILD_DIR/BUILD" "$RPM_BUILD_DIR/RPMS" "$RPM_BUILD_DIR/SOURCES"\ "$RPM_BUILD_DIR/SPECS" "$RPM_BUILD_DIR/SRPMS" if [ $? -ne 0 ] || [ ! -w "$RPM_BUILD_DIR" ]; then error "Couldn't create directory tree for building RPMs" fi } rpm_obtain_sources() { echo "--- Obtaining CAS sources for RPMs" generate_tar temp cp -v "$TEMP_DIR/$SOURCES_TAR_NAME" "$RPM_SOURCES_DIR" if [ ! -f "$RPM_SOURCES_DIR/$SOURCES_TAR_NAME" ]; then error "Couldn't obtain $SOURCES_TAR_NAME sources tarball!" fi } rpm_spec_prepare() { echo "--- Preparing SPEC file" if [ ! -f "$BASE_SPEC" ]; then error "SPEC file '$BASE_SPEC' not found" fi cp -v "$BASE_SPEC" "$RPM_SPECS_DIR/$NAME.spec" sed -i "s//$VERSION/g" "$RPM_SPECS_DIR/$NAME.spec" sed -i "s//$RELEASE/g" "$RPM_SPECS_DIR/$NAME.spec" if [ $DEBUG ]; then echo "--- Debug RPMs will be built as well" sed -i "s/%define debug_package %{nil}//g" "$RPM_SPECS_DIR/$NAME.spec" fi if [ ! -f "$RPM_SPECS_DIR/$NAME.spec" ]; then error "Couldn't create a SPEC file" fi } generate_rpm() { if [ $RPM_BUILT ]; then return 0 fi rpm_create_tree rpm_obtain_sources rpm_spec_prepare if [ ! $GENERATE_SRPM ] && [ $GENERATE_RPM ]; then echo "--- Building binary RPM packages" (HOME="$TEMP_DIR"; rpmbuild -bb "$RPM_SPECS_DIR/$NAME.spec") if [ $? -ne 0 ]; then error "Couldn't create RPM packages" fi mv -t "$OUTPUT_DIR" "$RPM_RPMS_DIR/$ARCH"/* fi if [ $GENERATE_SRPM ] && [ ! $GENERATE_RPM ]; then echo "--- Building source SRPM package" (HOME="$TEMP_DIR"; rpmbuild -bs "$RPM_SPECS_DIR/$NAME.spec") if [ $? -ne 0 ]; then error "Couldn't create SRPM package" fi mv -t "$OUTPUT_DIR" "$RPM_SRPMS_DIR"/* fi if [ $GENERATE_SRPM ] && [ $GENERATE_RPM ]; then echo "--- Building source and binary RPM packages" (HOME="$TEMP_DIR"; rpmbuild -ba "$RPM_SPECS_DIR/$NAME.spec") if [ $? -ne 0 ]; then error "Couldn't create RPM packages" fi mv -t "$OUTPUT_DIR" "$RPM_SRPMS_DIR"/* mv -t "$OUTPUT_DIR" "$RPM_RPMS_DIR/$ARCH"/* fi RPM_BUILT=1 } generate_srpm() { generate_rpm } if (( ! $# )); then invalid_usage "no arguments given\n$(usage)\n" fi while (( $# )); do case "$1" in tar) GENERATE_TAR=1 ;; zip) GENERATE_ZIP=1 ;; rpm) GENERATE_RPM=1 ;; srpm) GENERATE_SRPM=1 ;; version-only) VERSION_ONLY=1 ;; --output-dir|-o) OUTPUT_DIR="$2" dirname $OUTPUT_DIR &> /dev/null if [ $? -ne 0 ]; then invalid_usage "no output directory given after the '--output-dir' option" fi shift ;; --debug|-d) DEBUG=1 ;; --clean|-c) clean_all exit 0 ;; --help|-h) print_help exit 0 ;; *) if [ -d "$1" ]; then SOURCES_DIR=$(realpath "$1") else invalid_usage "option '$1' not recognized" fi ;; esac shift done check_options trap clean EXIT create_temp ### Variables that relates on arguments passed to this script: # By default all created packages will be put in: : ${OUTPUT_DIR:="$SOURCES_DIR/packages"} # Version file location: VERSION_FILE="$SOURCES_DIR/.metadata/cas_version" # RPM building directories: RPM_BUILD_DIR="$TEMP_DIR/rpmbuild" RPM_SOURCES_DIR="$RPM_BUILD_DIR/SOURCES" RPM_SPECS_DIR="$RPM_BUILD_DIR/SPECS" RPM_RPMS_DIR="$RPM_BUILD_DIR/RPMS" RPM_SRPMS_DIR="$RPM_BUILD_DIR/SRPMS" # CAS version generator location and output file name: CAS_VERSION_GEN="$SOURCES_DIR/modules/CAS_VERSION_GEN" CAS_VERSION_GEN_FILE="CAS_VERSION" check_version # CAS naming convention: CAS_FILENAME="$NAME-v$VERSION" # CAS sources archives filenames: SOURCES_TAR_NAME="$CAS_FILENAME.tar.gz" SOURCES_ZIP_NAME="$CAS_FILENAME.zip" # # Run the package generator script # info "\n=== Running OpenCAS '$VERSION-$RELEASE' package generator ===\n" if [ $VERSION_ONLY ]; then create_version_file exit 0 fi echo -n "Packages that will be built: " for package in ${!GENERATE_*}; do echo -en "\e[33m${package##*_}\e[0m " done echo -e "\n" check_dependencies create_version_file create_dir "$OUTPUT_DIR" for package in ${!GENERATE_*}; do ${package,,} done success