Travis CI build Racket Installation for Container-based - bash

My before_install in my .travis.yml reads
before_install:
- . scripts/get_racket.sh
- alias racket="${RACKET_DIR}/bin/racket"
I also have a script get_racket.sh which reads
#!/bin/bash
if [[ -z "$RACKET_VERSION" ]]; then
echo "Racket version environment variable not set, setting default"
export RACKET_VERSION=HEAD # set default Racket version
echo "Version: $RACKET_VERSION"
fi
if [[ -z "$RACKET_DIR" ]]; then
echo "Racket directory environment variable not set, setting default"
export RACKET_DIR='/usr/racket' # set default Racket directory
echo "Directory: $RACKET_DIR"
fi
if [ ! -e cache ] || [ ! -d cache ]; then
echo "Creating cache folder ..."
mkdir cache
fi
cd cache
INSTALL=$(ls | grep '^racket*.sh' | tr -d '[:blank:]')
if [[ ! -e "$RACKET_DIR" ]] || [[ ! -d "$RACKET_DIR" ]]; then
if [[ -z "$INSTALL" ]]; then
echo "Racket installation script not found, building."
if [ ! -e travis-racket ] || [ ! -d travis-racket ] \
|| [ ! -e travis-racket/install-racket.sh ] \
|| [ ! -f travis-racket/install-racket.sh ]; then
git clone https://github.com/greghendershott/travis-racket.git
fi
bash < travis-racket/install-racket.sh
else
"./$INSTALL"
fi
fi
which racket &>/dev/null
ESTATUS=$?
if [[ -n "$ESTATUS" ]]; then
echo "Adding racket to PATH"
export PATH="${PATH}:${RACKET_DIR}/bin"
fi
alias racket='$RACKET_DIR/bin/racket'
cd ..
but in a script that uses racket later in my build chain, I keep getting
racket: command not found
As you can see in the above snippets, I have tried a few workarounds to install (and later cache for faster builds) racket without sudo privileges (because this is a restriction of Travis CI's Container-based infrastructure). Any help would be much appreciated, I'm stumped.

You need to figure out whether this install script you've shown successfully puts a working Racket binary anywhere on the disk. Maybe it didn't even compile, or maybe it tried to install in /usr/bin, where you don't have write access without sudo, or maybe there's something wrong with the binary. Find the binary, make sure it works.
If it does work, you need to pay attention to where your script puts Racket. Does it go to /usr/bin, $HOME, or someplace else entirely?
Finally, you need to figure out where the failing script is looking for Racket. The line where you set the $PATH will not affect the $PATH as seen from another shell script. I'd bet it's installing somewhere that's not in the default $PATH, and your failing script is looking only in the default $PATH.

Related

'source' statement and 'function' declaration at end of .bashrc interfere with one another

At first I created a script to 'find' a file and switch to that directory. Alas, upon returning from the script, the 'cd' was unchanged. Directory changes within a script are local to that script. I forgot. Sue me.
So... I created that same code as a function in the middle of .bashrc. When I re-enter the Bash shell, the function is not defined or visible. So... I placed the function at the end of .bashrc and -- voila! -- it worked. Here is the function:
function goto {
if [[ "$1" == "" ]]
then
echo "[ERROR] $0 requires a filename as input."
echo "[INFO] Usage: $0 <filename> finds file and changes to that directory."
else
echo "[INFO] Looking for file: $1"
declare -x -a full_filepath=$(find . -name "$1")
if [[ "${full_filepath[0]}" == "" ]]
then
echo "[ERROR] Unable to find requested file $1. Exiting..."
else
local filepath=${full_filepath[0]%/*}
local filename=${full_filepath[0]##*/}
echo "[INFO] Switching to $filepath to locate $filename..."
cd $filepath
fi
fi
}
Now here's the problem. I had to move it after SDKMan's init code in .bashrc (ignoring the warning that #THIS MUST BE AT THE END OF THE FILE FOR SDKMAN TO WORK!!!). Not surprisingly, 'sdk' no longer works.
Is there a "right way" to include a function in .bashrc so that other scripts like SDKMan's can remain at the end, for whatever-in-gods-name reason it must be there...???
I uninstalled then reinstalled SDKMan and the functions are now working as is SDKMan.
The conditional they add is odd. It reminds me of the shortcuts in Perl.
Here is the code added to .bashrc:
#THIS MUST BE AT THE END OF THE FILE FOR SDKMAN TO WORK!!!
export SDKMAN_DIR="/home/peter/.sdkman"
[[ -s "/home/peter/.sdkman/bin/sdkman-init.sh ]] && source "/home/peter/.sdkman/bin/sdkman-init.sh
This works just as well:
if [[ -s "/home/peter/.sdkman/bin/sdkman-init-sh" ]]; then source "/home/peter/.sdkman/bin/sdkman-init-sh"; fi
but it's a few characters longer, I guess. And if they had used the var they just defined above it, it would be even shorter:
if [[ -s "$SDKMAN_DIR/bin/sdkman-init-sh" ]]; then source "$SDKMAN_DIR/bin/sdkman-init-sh"; fi
Barmar: You were right. Location in .bashrc doesn't matter. Thanks.
Wiimm: Thanks for the tip.
Mark: For good measure, I've exported the functions. Thanks.

BASH How to check if given argument is command name?

How, in BASH, I could check if a given argument to a script is a "commands name"?
For example: I know that you can check if a path is a folder with [[ -d $path ]] or if it is plain file with [[ -f $path ]].
I want that my ./script will only accept commands name.
With [[ -f "$path" && -x "$path" ]] you can check if it is a file and it has execution permissions, you can see the full list of expressions in man test.
This way you check if the argument can be executed directly from the shell (for example: if <command> is ls this return Yes, if <command> is las this will return No).
if [[ `which <command> &> /dev/null` ]]; then
echo "Yes";
else
echo "No";
fi
With a simpler [[ -f $path && -x $path ]] you can check if $path can be executed... but this does not mean that writing the "name of the command" in the shell, it will be executed (you have to make sure that the $path is in the $PATH environmental variable.
A simple script that uses the idea above and exit in the case the argument is not a command could be something like:
#!/bin/bash
if [[ `which $1 &> /dev/null` ]]; then
echo "Execute the script"
else
echo "Error! Usage: "`basename $0`" <command_name>"
fi
Tell if you need something different...
Hi if i understand you right you can try the following:
SCRIPTNAME=$(basename "$0") # in your case -> script
Now you can check this:
if [ SCRIPTNAME -eq "$SCRIPTNAME" ]
then
# your stuff here
fi
Or do you want something other?

In bash script Symlink are not getting created even though the commands are executed successfully

I am new to RPM Package enhancement/development and working on post-install script.
I want to achieve the symbolic links creation on execution of post-install script but stuck on a issue.
The script execution is working fine for symbolic link creation but for Upgrade part when I check the Symbolic links in "$RPM_pckg_home/bin" they not getting created though the commands are executed successfully.
Here is the sample code;
Original_bin_path=/a/b/c
RPM_pckg_home=/d/e/f
if [[ "$1" -eq 1 ]]; then # 1 for install
cd $RPM_pckg_home/bin
for cmd in `ls Original_bin_path` ; do
ln -s $Original_bin_path/${cmd} ${cmd}
done
elif [[ "$1" -eq 2 ]]; then # 2 for Upgrade
cd $RPM_pckg_home/bin
for cmd in `ls Original_bin_path` ; do
rm ${cmd}
ln -s $Original_bin_path/${cmd} ${cmd}
done
fi
Could you please suggest where would be the issue.
Aside from the possible typo, this is how you should write your loop:
if [[ "$1" -eq 1 ]]; then # 1 for install
for cmd in "$Original_bin_path"/* ; do
ln -s "${cmd}" "$RPM_pckg_home/bin"
done
elif [[ "$1" -eq 2 ]]; then # 2 for Upgrade
for cmd in "$Original_bin_path"/*; do
rm "${cmd}"
ln -s "${cmd}" "$RPM_pckg_home/bin"
done
fi
Instead of iterating over the output of ls, just iterate over the files that match the glob, and modify your rm and ln commands to accommodate the change in the value of $cmd.

Using 'grep' in nested if-statement

I'm still finding my way around bash scripting so please bear with me.
At the moment I am trying to write a script that checks a few on a server.
Once check is to see if the GPU driver has is the latest version.
However regardless of the installed GPU driver on the server, the script returns GPU is not upgraded
Here is the code:
#!/bin/bash -x
######################################################
#GENERAL VARIABLES
GPU_DRIVER=270.41.19
######################################################
#Checking if Packsges are Installed
if [ $(uname -r) != $KERNEL_VERSION ]
then
echo "Kernel is not Upgraded"
#INSTALL KENRENL!
#REBOOT!
else if [ ! $(nvidia-smi -q |grep -q $GPU_DRIVER) ]
then
echo "GPU is not Upgraded"
else if [ $(cat /usr/ort/build_number) != $CODE_RELEASE ]
then
echo "Code Release526 Has not Been Installed"
fi
fi
fi
I would like to know why the condition in the if-statement does not apply?
NOTE:
The output of the nvidia-smi looks similar to below:
:~/script$ nvidia-smi -q|grep Driver
Driver Version : 270.41.19
Driver Model
You want to test whether a grep succeeded or failed. That does not require [...] or $(...). You merely need to execute the grep. Contrary to popular belief, [ is not part of the if statement syntax; it is a bash command which succeeds or fails based on the evaluation of a conditional expression. (Usually, you would want to use [[, which is a better conditional evaluator.) The if statement is followed by a series of ordinary bash statements; followed by the keyword then. If the last statement succeeds, the then branch is taken; otherwise the else branch is taken.
Change
else if [ ! $(nvidia-smi -q |grep -q $GPU_DRIVER) ]
to
elif ! nvidia-smi -q | grep -q -F "$GPU_DRIVER"; then
(And the elif will remove the need for the fi matching that if.)
Aside from removing the test built-in ([), I fixed a couple of other things:
grep normally expects patterns to be regexes. In a regex, a . matches any character. I think you are looking for a precise match, so I added the -F flag.
And I put quotes around the $GPU_DRIVER, just in case.
To explain the if ... then ... elif ... fi syntax, here's the entire if statement:
if [[ $(uname -r) != $KERNEL_VERSION ]]; then
echo "Kernel is not Upgraded"
#INSTALL KENRENL!
#REBOOT!
elif ! nvidia-smi -q |grep -q -F "$GPU_DRIVER"; then
echo "GPU is not Upgraded"
elif [[ $(cat /usr/ort/build_number) != $CODE_RELEASE ]]; then
echo "Code Release526 Has not Been Installed"
fi
The grep -q does't return/print anything. It actually sets the return value as 0 or 1. You can check this using $?. So effectively your if statement becomes
[ ! $() ]
The $() returns false always. This results in the behavior you have defined.

How to get shell to self-detect using zsh or bash

I've a question on how to tell which shell the user is using. Suppose a script that if the user is using zsh, then put PATH to his .zshrc and if using bash should put in .bashrc. And set rvmrc accordingly.
#!/usr/bin/env bash
export PATH='/usr/local/bin:$PATH' >> ~/.zshrc
source ~/.zshrc
I've tried the following but it does not work : (
if [[ $0 == "bash" ]]; then
export PATH='/usr/local/bin:$PATH' >> ~/.bashrc
elif [[ $0 == "zsh" ]]; then
export PATH='/usr/local/bin:$PATH' >> ~/.zshrc
fi
# ... more commands ...
if [[ $0 == "bash" ]]; then
[[ -s '/Users/`whoami`/.rvm/scripts/rvm' ]] && source '/Users/`whoami`/.rvm/scripts/rvm' >> ~/.bashrc
source ~/.bashrc
elif [[ $0 == "zsh" ]]; then
[[ -s '/Users/`whoami`/.rvm/scripts/rvm' ]] && source '/Users/`whoami`/.rvm/scripts/rvm' >> ~/.zshrc
source ~/.zshrc
fi
If the shell is Zsh, the variable $ZSH_VERSION is defined. Likewise for Bash and $BASH_VERSION.
if [ -n "$ZSH_VERSION" ]; then
# assume Zsh
elif [ -n "$BASH_VERSION" ]; then
# assume Bash
else
# assume something else
fi
However, these variables only tell you which shell is being used to run the above code. So you would have to source this fragment in the user's shell.
As an alternative, you could use the $SHELL environment variable (which should contain absolute path to the user's preferred shell) and guess the shell from the value of that variable:
case $SHELL in
*/zsh)
# assume Zsh
;;
*/bash)
# assume Bash
;;
*)
# assume something else
esac
Of course the above will fail when /bin/sh is a symlink to /bin/bash.
If you want to rely on $SHELL, it is safer to actually execute some code:
if [ -n "$($SHELL -c 'echo $ZSH_VERSION')" ]; then
# assume Zsh
elif [ -n "$($SHELL -c 'echo $BASH_VERSION')" ]; then
# assume Bash
else
# assume something else
fi
This last suggestion can be run from a script regardless of which shell is used to run the script.
Just do echo $0
it says -zsh if it's zsh and -bash if it's bash
EDIT: Sometimes it returns -zsh and sometimes zsh and the same with bash, idk why.
A word of warning: the question you seem to have asked, the question you meant to ask, and the question you should have asked are three different things.
“Which shell the user is using” is ambiguous. Your attempt looks like you're trying to determine which shell is executing your script. That's always going to be whatever you put in the #! line of the script, unless you meant your users to edit that script, so this isn't useful to you.
What you meant to ask, I think, is what the user's favorite shell is. This can't be determined fully reliably, but you can cover most cases. Check the SHELL environment variable. If it contains fish, zsh, bash, ksh or tcsh, the user's favorite shell is probably that shell. However, this is the wrong question for your problem.
Files like .bashrc, .zshrc, .cshrc and so on are shell initialization files. They are not the right place to define environment variables. An environment variable defined there would only be available in a terminal where the user launched that shell and not in programs started from a GUI. The definition would also override any customization the user may have done in a subsession.
The right place to define an environment variable is in a session startup file. This is mostly unrelated to the user's choice of shell. Unfortunately, there's no single place to define environment variables. On a lot of systems, ~/.profile will work, but this is not universal. See https://unix.stackexchange.com/questions/4621/correctly-setting-environment and the other posts I link to there for a longer discussion.
You can simply try
echo $SHELL
the other answers fail with set -u
if [ ! -z ${ZSH_VERSION+x} ]; then
echo "this is zsh"
echo ${(%):-%x}
elif [ ! -z ${BASH_VERSION+x} ]; then
echo "this is bash"
echo $BASH_SOURCE
else
echo "not recognized"
fi
An alternative, might not work for all shells.
for x in $(ps -p $$)
do
ans=$x
done
echo $ans
Myself having a similar problem, settled for:
_shell="$(ps -p $$ --no-headers -o comm=)"
if [[ $_shell == "zsh" ]]; then
read -q -s "?Do it?: "
fi
elif [[ $_shell == "bash" || $_shell == "sh" ]]; then
read -n 1 -s -p "Do it [y/n] "
fi
Here is how I am doing it based on a previous answer from Gilles :
if [ -n "$ZSH_VERSION" ]; then
SHELL_PROFILE="$HOME/.zprofile"
else
SHELL_PROFILE="$HOME/.bash_profile"
fi
echo "export VAR1=whatever" >> $SHELL_PROFILE
echo "INFO: Refreshing your shell profile: $SHELL_PROFILE"
if [ -n "$ZSH_VERSION" ]; then
exec zsh --login
else
source $SHELL_PROFILE
fi

Resources