Simple Directory Watcher to Restart Dev Server
Tags: zsh, linux, development, scripting
Published: 2024-06-27 17:44:59

Simple Linux script that restarts the dev server on file changes. Couldn't find it so I made it.

## Intro
I have been learning [Go](https://go.dev/) and I came across a pretty basic problem. I was practicing making a REST API web server and I wanted to enable hot reloading so my changes would be visible while I am changing the code. This is a common workflow when using a development server. 

Ever since I have been making APIs there was always a simple way to enable hot reloading. It is easy in Go too, you just have to use [air](https://github.com/air-verse/air). It so simple, just write `air` and you have hot reloading. Now you may ask the question that if it's so great what this post is for?

## My script
It all started when `air` decided to freeze multiple times. I searched a few and found no quick solution so I started to think about a solution. By my understanding air basically just executes the command that runs the web server (in this case `go run .`). 

Do I really need a whole Go library to do that? There must be a lighter or in other words Linux solution. I came across few solutions but not all had the capability to handle *all* types of directory changes. I wanted to be able to watch for file: create, edit, move, delete. For example [`entr`](https://github.com/eradman/entr) doesn't rerun the command when a new file is added to the directory that is being watched.

Then I discovered [`inotify-tools`](https://github.com/inotify-tools/inotify-tools) and inside it [`inotifywait`](https://linux.die.net/man/1/inotifywait). This tool can do all kinds of file changes that I wanted. So now I only had to create a script which can run the specified command and also is able to kill the process and rerun the command. 

**The script takes whatever args are passed into it and runs that and restarts it whenever a file change happens in the current directory. I also made it so via `--we-exclude=[PATHS]` you can pass inotify what to [exlude from watching](https://linux.die.net/man/1/inotifywait).**

```zsh
#!/usr/bin/env zsh

if ! command -v inotifywait > /dev/null; then
  print -P "%F{red}Can't start: inotifywait not found.%f"
  exit
fi

we_exclude_value=""
command_to_exec=""
for arg in "$@"; do
    if [[ $arg == "--we-exclude="* ]]; then
        we_exclude_value="${arg#*=}"
        break
    else
      command_to_exec+="$arg "
    fi
done

command_to_exec=${command_to_exec% }

while true; do
  print -P "$(date +%T): %F{green}Restarting...%f"
  $@ &
  PID=$!
  inotifywait --event=modify,move,create,delete,delete_self --recursive . --exclude=$we_exclude_value > /dev/null 2>&1
  pkill -P $PID 2>/dev/null
  kill $PID 2>/dev/null
  wait $PID 2>/dev/null
done
```

The script is also [available in my GitHub .dotfiles repository under the scripts directory](https://github.com/11Firefox11/.dotfiles/blob/main/bin/.local/scripts/watch-execute).

If you are interested in more of this type of content then I suggest you to read posts from [my series about improving my setup and developer productivity](https://tomoviktor.com/series/developer-productivity/page/1/).