install_sdp_ruby.sh #1

  • //
  • guest/
  • perforce_software/
  • sdp/
  • main/
  • Server/
  • Unix/
  • setup/
  • install_sdp_ruby.sh
  • View
  • Commits
  • Open Download .zip Download (16 KB)
#!/bin/bash
#------------------------------------------------------------------------------
set -u

#==============================================================================
# Internal Functions

#------------------------------------------------------------------------------
# Function msg ($message)
#
# Input:
#  Arg 1, $message, message to display.
#
# Sample Usage:
# msg "This is a good message."
#------------------------------------------------------------------------------
function msg () { echo -e "$*"; }

#------------------------------------------------------------------------------
# Function bail ($message, [$exitCode])
#
# Input:
#  Arg 1, $message, error message to display.
#  Arg 2, $exitCode, exit status. Default is 1.
#
# Sample Usage:
# bail "Something went wrong"
#------------------------------------------------------------------------------
function bail () {
   msg "Error: ${1:-Unknown Error}\n"
   msg "Aborting after $(($SECONDS/3600)) hours $(($SECONDS%3600/60)) minutes $(($SECONDS%60)) seconds.\n"

   exit ${2:-1}
}

#------------------------------------------------------------------------------
# Function cmd ($command, [$desc], $[log], [$showLog])
#
# Input:
#  Arg 1, $command, the command to run.
#  Arg 2, $description, optional description to show before running the
#  command
#  Arg 3, $log, name of file to log to, e.g. 'make.log'.  Can be relative
#  or absolute path.
#  Arg 4, $showLog: Determines whether to cat the output of $log. Values:
#  0=never, 1=always, 2=on non-zero exit of command only.
#  The default is 1 (always).
#
# Usage Samples:
# cmd "ls" "Listing directory" || bail "Failed to list dir." 
# cmd "make test" "Building and Testing" make_test.log 2
#------------------------------------------------------------------------------
function cmd () {
   declare command="${1:-echo}"
   declare desc="${2:-}"
   declare log="${3:-}"
   declare showLog=${4:-1}
   declare -i exitCode

   [[ -n "${desc:-}" ]] && msg "$desc"

   if [[ $NO_OP -eq 0 ]]; then
      if [[ -n "$log" ]]; then
         msg "Executing: $command, logging to $log."
         $command > $log 2>&1
         exitCode=$?
         if [[ $showLog -ne 0 ]]; then
            if [[ $showLog -eq 1 ]]; then
               msg "Output of $log:\n"
               cat $log
            elif [[ $exitCode -ne 0 ]]; then
               msg "Command failed.  Output of $log:\n"
               cat $log
            fi
         fi
      else
         msg "Executing: $command"
         $command
         exitCode=$?
      fi
   else
      msg "NO_OP: Would run: $command"
      exitCode=0
   fi
   return $exitCode
}

#------------------------------------------------------------------------------
# Function: terminate
function terminate
{
   # Disable signal trapping.
   trap - EXIT SIGINT SIGTERM

   # Stop logging.
   [[ "${LogFile}" == off ]] || msg "LogFile is $LogFile\n${H1}\n"

   # With the trap removed, exit.
   exit $OverallReturnStatus
}

#------------------------------------------------------------------------------
# Function: usage (required function)
#
# Input:
# $1 - style, either -h (for short form) or -man (for man-page like format).
# The default is -h.
#
# $2 - error message (optional).  Specify this if usage() is called due to
# user error, in which case the given message displayed first, followed by the
# standard usage message (short or long depending on $1).  If displaying an
# errror, usually $1 should be -h so that the longer usage message doesn't
# obsure the error message.
#
# Sample Usage:
# usage
# usage -h
# usage -man
# usage -h "Incorrect command line usage."
#------------------------------------------------------------------------------
function usage
{
   declare style=${1:--h}
   declare errorMessage=${2:-Unset}

   if [[ $errorMessage != Unset ]]; then
      echo -e "\n\nUsage Error:\n\n$errorMessage\n\n"
   fi

   echo "USAGE for $ThisScript v$Version:

$ThisScript [-e <ruby_root> | -r <ruby_root> [-p <ruby_rel>] [-d <ruby_config_defs>]] [-a] [-b <p4ruby_branch>] [-a <api_rel>] [-C] [-s] [-L <log>] [-n] [-D]

or

$ThisScript [-h|-man]
"
   if [[ $style == -man ]]; then
      echo -e "
DESCRIPTION:
	This script downloads Ruby source code, the Perforce C++ API in binary form,
	and the P4Ruby gem.  It builds, tests, and installs Ruby, and then installs
	P4Ruby.

	Optionally, if the '-e /path/to/my/ruby' flag is used, an existing Ruby
	installation is updated with P4Ruby In that case, the P4Ruby gem and the
	Perforce C++ API in binary form are downloaded, and only P4Ruby is installed.

OPTIONS:
 -e <path_to_existing_ruby_root>
	Specify the path to the install root of an existing existing Ruby installation.
	This directory will typically include bin, man, lib, and possibly other
	directories.

	The '-e' option cannot be used with '-r' or '-p'.

 -r	Specify the Ruby install root.  The default is $InstallRoot.
	The user running this script may require sudo priviledges depending
	on the install root used.

	Install will be attempted without sudo first.  If the install fails,
	it will be attempted a second time with sudo (unless already running
	as root).

	Cannot be used with '-e'.

 -p	Specify the Ruby version, e.g. 2.4.1.  The default is $RubyRel.

	Cannot be used with '-e'.

 -a	Specify the Perforce API to use.  The default is $P4APIRel.

 -b	Specify the release branch of P4Ruby to acquire source from, e.g. '-b r15.2'
	to build the 2015.2 release, or '-b main' to build from the Ruby
	mainline.  The version specified must be available as
	http://ftp.perforce.com/perforce/<branch>/bin.tools/p4ruby.tgz.

	NOTE: This is currently configured to pull from the Perforce FTP
	server. It may at some point be updated to pull P4Ruby from
	The Workshop, Perforce's open source repository.  Specifying '-b main'
	is not available when connected to the ftp server, but may be when
	connected to The Workshop, if and when that happens.

 -C	Specify -C to remove the working directory, including the
	downloads directory. This can be used to ensure a clean start
	point, e.g. if multiple iterations are needed to achieve a successful
	install.

 -f	Force thru, ignoring failed tests.  By default, if the test suite for
	Ruby fails, this script aborts, making it harder (by design) to accidentally
	ignore the test failures.  In some cases, test failures may be deemed safely
	ignorable; this flag is for those scenarios.

 -s	Specify '-s' to build and install Ruby only, skipping P4Ruby installation.

 -L <log>
	Specify the path to a log file, or the special value 'off' to disable
	logging.  By default, all output (stdout and stderr) goes to:
	${LogFile}.

 -n	No-Op.  Prints commands instead of running them.

 -D     Set extreme debugging verbosity.

HELP OPTIONS:
 -h	Display short help message
 -man	Display man-style help message

REQUIREMENTS:
	This script requires a public internet connection with 'http:' access
	to ftp.perforce.com and www.ruby-lang.org.

	It requires the 'curl' utility, the g++ compiler, and 'make', and the
	'rubygem-bundle' package.

EXAMPLES:
	Example 1: Typical usage, building a local Ruby/P4Ruby in
	/home/perforce/ruby, using Ruby v$RubyRel, building P4Ruby from the
	$P4RubyRel branch in The Workshop using the $P4APIRel release of
	the Perforce C++ API:
	$ThisScript -r /home/perforce/ruby

	Example 2: Build only Ruby, v2.4.1, for testing, skipping P4Ruby build:
	$ThisScript -r /tmp/test_ruby_2.4.1 -p 2.4.1 -s

	Example 3:  Add P4Ruby from the mainline branch in The Workshop to the
	just-built existing Ruby from the prior example:
	$ThisScript -e /tmp/test_ruby_2.4.1 -b main

	Example 4:  Add P4Ruby from the $P4RubyRel branch in The Workshop to
	an existing Ruby in your environment
	$ThisScript -e /devtools/ruby
"
   fi

   exit 1
}

#==============================================================================
# Declarations
declare InstallRoot="/p4/common/ruby"
declare WorkingDir="${P4TMP:-/tmp}/p4ruby"
declare DownloadsDir=
declare RubyRel="2.4.1"
declare RubyTarFile=
declare RubyBuildDir=
declare RubyURL=
declare P4APIRel="r15.2"
declare Platform=
declare P4APIURL=
declare P4APITarFile="p4api.tgz"
declare P4APIDir=
declare P4RubyRel="r15.2"
declare P4RubyTarFile="p4ruby.tgz"
declare P4RubyURL=
declare P4RubyBuildDir=
declare ThisScript=${0##*/}
declare CommandLine="$ThisScript $*"
declare LogFile="${LOGS:-/tmp}/$ThisScript.$(date +'%Y%m%d-%H%M%S').log"
declare H1="==============================================================================="
declare H2="-------------------------------------------------------------------------------"
declare RubyConfigDefs=
declare -i IgnoreFailedTests=0
declare -i UseExistingRuby=0
declare -i SkipP4Ruby=0
declare -i CleanWorkingDir=0
export NO_OP=0
declare Version="1.0.6"

#==============================================================================
# Command Line Processing

declare -i shiftArgs=0

set +u
while [[ $# -gt 0 ]]; do
   case $1 in
      (-r) InstallRoot="$2"; shiftArgs=1;;
      (-e) InstallRoot="$2"; UseExistingRuby=1; shiftArgs=1;;
      (-p) RubyRel="$2"; shiftArgs=1;;
      (-d) RubyConfigDefs="$2"; shiftArgs=1;;
      (-f) IgnoreFailedTests=1;;
      (-a) P4APIRel="$2"; shiftArgs=1;;
      (-b) P4RubyRel="$2"; shiftArgs=1;;
      (-C) CleanWorkingDir=1;;
      (-s) SkipP4Ruby=1;;
      (-h) usage -h;;
      (-man) usage -man;;
      (-n) export NO_OP=1;;
      (-D) set -x;; # Debug; use 'set -x' mode.
      (*) usage -h "Unknown arg ($1).";;
   esac

   # Shift (modify $#) the appropriate number of times.
   shift; while [[ $shiftArgs -gt 0 ]]; do
      [[ $# -eq 0 ]] && usage -h "Incorrect number of arguments."
      shiftArgs=$shiftArgs-1
      shift
   done
done
set -u

#==============================================================================
# Main Program

trap terminate EXIT SIGINT SIGTERM

declare -i OverallReturnStatus=0

if [[ "${LogFile}" != off ]]; then
   touch ${LogFile} || bail "Couldn't touch log file [${LogFile}]."

   # Redirect stdout and stderr to a log file.
   exec > >(tee ${LogFile})
   exec 2>&1

fi

msg "${H1}\nStarting ${0##*/} v$Version at $(date).\n"

msg "Started with this command line:\n\t$CommandLine\n"

[[ -z "$(which bundle 2>/dev/null)" ]] &&\
   bail "Missing required 'bundle' utility.  Try installing the package 'rubygem-bundler' package and try again."

if [[ $UseExistingRuby -eq 1 ]]; then
   RubyTarFile=
   RubyURL=
else
   if [[ -d "$InstallRoot" ]]; then
      MovedAsideDir="${InstallRoot}.MOVED.$(date +'%Y%m%d-%H%M')"
      cmd "mv ${InstallRoot} $MovedAsideDir" \
         "Moved existing InstallRoot aside to $MovedAsideDir" ||\
         bail "Failed to move existing IntallRoot dir [$InstallRoot] aside."
   fi

   RubyTarFile="ruby-${RubyRel}.tar.gz"
   RubyMajorMinor=${RubyRel%.*}
   RubyURL="https://cache.ruby-lang.org/pub/ruby/${RubyMajorMinor}/$RubyTarFile"
fi

if [[ $SkipP4Ruby -eq 0 ]]; then
   case "$(uname)" in
      (Linux)
         Platform="linux26x86"
         [[ "$(uname -m)" == *"_64" ]] && Platform="${Platform}_64"
      ;;
      (Darwin)
         Platform="darwin90x86"
         [[ "$(uname -m)" == *"_64" ]] && Platform="${Platform}_64"
      ;;
      (*)
         bail "Current OS/platform is not supported: $(uname -a)."
      ;;
   esac

   msg "Target platform is: $Platform."

   P4APIURL="http://ftp.perforce.com/perforce/$P4APIRel/bin.$Platform/$P4APITarFile"
   #P4RubyURL="https://swarm.workshop.perforce.com/downloads/p4ruby-bld/$P4RubyRel/downloads/$P4RubyTarFile"
   P4RubyURL="ftp://ftp.perforce.com/perforce/$P4RubyRel/bin.tools/$P4RubyTarFile"
else
   P4APITarFile=
   P4RubyTarFile=
fi

DownloadsDir="${WorkingDir}/downloads"

if [[ -d "$WorkingDir" ]]; then
   if [[ $CleanWorkingDir -eq 0 ]]; then
      msg "Using existing working dir: $WorkingDir"
   else
      cmd "/bin/rm -rf $WorkingDir" "Removing existing working dir due to -C." ||\
         bail "Failed to remove working dir $WorkingDir."
   fi
else
   mkdir -p "$WorkingDir" || bail "Failed to create working dir $WorkingDir"
fi

if [[ ! -d "$DownloadsDir" ]]; then
   mkdir -p "$DownloadsDir" || bail "Failed to create downloads dir $DownloadsDir."
fi

cd "$DownloadsDir" || bail "Could not cd to downloads dir $DownloadsDir."

msg "${H1}\nOperating in downloads dir [$DownloadsDir]."

if [[ $UseExistingRuby -eq 0 ]]; then
   if [[ -r "$RubyTarFile" ]]; then
      msg "Using existing downloaded Ruby tar file $PWD/$RubyTarFile."
   else
      cmd "curl -s -O $RubyURL" "Downloading Ruby source code." ||\
         bail "Failed to download Ruby from URL $RubyURL."
   fi
fi

if [[ $SkipP4Ruby -eq 0 ]]; then
   if [[ -r "$P4APITarFile" ]]; then
      msg "Using existing downloaded P4 C++ API tar file $PWD/$P4APITarFile."
   else
      cmd "curl -s -O $P4APIURL" "Downloading Perforce C++ API." ||\
         bail "Failed to download Perforce C++ API from URL $P4APIURL."
   fi

   if [[ -r "$P4RubyTarFile" ]]; then
      msg "Using existing downloaded P4Ruby tar file $PWD/$P4RubyTarFile."
   else
      cmd "curl -k -s -O $P4RubyURL" "Downloading P4Ruby Source." ||\
         bail "Failed to download P4Ruby Source fromm URL $P4RubyURL"
   fi
fi

cd "$WorkingDir" || bail "Could not cd to working dir $WorkingDir."
msg "${H1}\nOperating in working dir [$WorkingDir]."

for tarfile in $RubyTarFile $P4APITarFile $P4RubyTarFile; do
   cmd "tar -xzf $DownloadsDir/$tarfile" "Extracting $tarfile." ||\
      bail "Failed to extract tar file $tarfile."
done

if [[ $UseExistingRuby -eq 0 ]]; then
   RubyBuildDir="$PWD/ruby-$RubyRel"

   cd $RubyBuildDir || bail "Could not cd to Ruby build dir $RubyBuildDir."
   msg "${H1}\nOperating in Ruby build dir [$RubyBuildDir]."

   cmd "autoconf" "${H2}\nRunning autoconf."

   cmd "./configure --prefix=$InstallRoot $RubyConfigDefs" "${H2}\nConfiguring Ruby" configure.log ||\
      bail "Failed to configure Ruby."

   cmd "make" "${H2}\nMaking Ruby" make.log || bail "Failed to build Ruby"

   cmd "make test" "${H2}\nTesting Ruby" make_test.log
   if [[ $? -eq 0 ]]; then
      msg "Verified: Ruby Test Suite passed."
   else
      if [[ $IgnoreFailedTests -eq 1 ]]; then
         msg "Warning: Ruby Test Suite was not entirely successful. Ignoring due to -f."
      else
         bail "Ruby Test Suite failed."
      fi
   fi

   cmd "make install" "${H2}\nInstalling Ruby to $InstallRoot" make_install.log
   if [[ $? -ne 0 ]]; then
      if [[ $(id -u) -eq 0 ]]; then
         bail "Install for Ruby failed running as root."
      else
         msg "Install for Ruby failed as $(whoami).  Trying again with sudo."
         cmd "sudo make install" "\nInstalling Ruby using sudo." make_install_sudo.log ||\
            bail "Failed to install Ruby with sudo to $InstallRoot."
      fi
   fi
fi

if [[ $SkipP4Ruby -eq 0 ]]; then

   P4APIDir="$(ls -t -d $WorkingDir/p4api-* | head -1)"
   P4RubyBuildDir="$(ls -d $WorkingDir/p4ruby)"

   msg "${H2}\nInstalling P4Ruby gem under $InstallRoot."

   cd $P4RubyBuildDir || "Could not cd to P4Ruby build dir $P4RubyBuildDir."

   msg "${H1}\nOperating in P4Ruby build dir [$P4RubyBuildDir]."

   cmd "bundle" "Doing the ruby bundle thing." ||\
      bail "Ruby bundling failed."

   cmd "gem install p4ruby -- --with-p4api-dir=$P4APIDir" ||\
      bail "Failed to install P4Ruby."

   if [[ $NO_OP -eq 0 ]]; then
      msg "Smoke Testing P4Ruby with command:\n$InstallRoot/bin/ruby -rP4 -e \"puts P4.identify\""
      $InstallRoot/bin/ruby -rP4 -e "puts P4.identify"
      if [[ $? -eq 0 ]]; then
         msg "\nSmoke test was successful!\n\nRuby scripts should use this shebang line:\n#!$InstallRoot/bin/ruby\n\nOptionally, prepend PATH with $InstallRoot/bin, and prepend MANPATH with $InstallRoot/man\n"
      else
         OverallReturnStatus=1
      fi
   fi
fi

if [[ $OverallReturnStatus -eq 0 ]]; then
   msg "${H1}\nAll processing completed successfully.\n"
else
   msg "${H1}\nProcessing completed, but with errors.  Scan above output carefully.\n" 
fi

msg "That took $(($SECONDS/3600)) hours $(($SECONDS%3600/60)) minutes $(($SECONDS%60)) seconds.\n"

# Change User Description Committed
#2 27331 C. Thomas Tyler Released SDP 2020.1.27325 (2021/01/29).
Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'.
#1 23006 C. Thomas Tyler Released SDP 2017.3.23003 (2017/10/19).
Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'.
//guest/perforce_software/sdp/dev/Server/Unix/setup/install_sdp_ruby.sh
#1 22692 C. Thomas Tyler Added install_sdp_ruby.sh script to install Ruby and P4Ruby in
/p4/common/ruby, complimenting the other SDP install scripts for
Perl and Python.