2 minute read

If you haven’t read part 1, click here!

There were a few improvements from last time that I wanted to implement.

  1. Refactor each separate chunk of installations into separate files
  2. Write more re-usable functions to be shared across sets of installs
  3. Add more installations/basic features

Let’s start with #3. In the first couple of commits, i added a few more integrations like slack, skype, etc etc.

For #2, I had originally started with a ‘get-it-done’ mentality. Even if the code wasn’t particularly pretty, I wanted to align to my basic design principle of idempotency. Because of that, I added quite a bit more fluff in terms of content than absolutely necessary. In the book, Clean Code, the author mentions that it takes a lot of refactoring to get to the “ideal” state. With that in mind, I tried to take it easier and just code and get everything down and functional.

verify_cask() {
  if [[ $(brew cask list | grep $1 | head -c1 | wc -c) -eq 0 ]]; then
    echo ${1}":: not installed" | awk '{print toupper($0)}'
    $2
    verify_cask $1 $2
  else
    echo ${1}":: installed" | awk '{print toupper($0)}'
  fi
}

Even though I had a basic verify_program method, I created a separate one because the command to verify installations for bash versus casks were different. However, the general breakdown of the method was the same. In my main method, I use individual install_X methods to make my calls.

verify_cask slack install_slack

There is a really neat utility for statically analyzing sh scripts called shellcheck. There’s an online version as well as one that can be used via terminal/brew. With this tool, I received some pointers on how I could make the code more robust. The snippet above became this:

verify_cask() {
  if "$1" -v | grep -q "no ${1}" || [[ $("$1" -v | head -c1 | wc -c) -eq 0 ]]; then
    echo "${1}:: not installed" | awk '{print toupper($0)}'
    verify_program "$1" "$2"
  else
      echo "${1}:: installed" | awk '{print toupper($0)}'
  fi
}

Note the quoting around the parameter substitutions, for more overtly clear indication of what substitution is happening.

The following commit was more substantial because I made use of the array data structure in bash and iterated through the respective verify methods for each type of installation, hence achieving more re-usability. individual installation calls became:

brews=(
  ruby
  node
)

for BREW in "${brews[@]}" 
do 
  :
  verify_brew "$BREW"
done

That being said, all the code was in a mega script. The next commit resolved this issue by chunking everything up into separate scripts that are grouped by the type of installation, ie. brews.sh, casks.sh, alias.sh. This led to a much nicer view of the main script:

main() {
  # import other scripts
  . lib/alias.sh
  . lib/brews.sh
  . lib/casks.sh

   # create main working folder
   cd ~ || exit

For more functionality, I also included some fancy ruby gems as well as a more extensive list of vscode extensions.

Otherwise, sorry for the short post. A lot of real-life happening these past two weeks but I’ll be back with more soon. As always, the code can be found on my GitHub, here.