Automatically run scripts from inside their directory with watchexec
Rust First
This is a rust version of the script. Putting it here for now until I can redo the post to include it more directly.
#!/bin/bash
Run Where I Made Ya
I use a bunch of
I cooked up this little script to take care of that with watchexec2:
#!/bin/bash
The script sits at the top of Neopolitan's source tree. It kicks off a watchexec process that keeps an eye on Python files. When one changes watchexec runs it.
The key feature is that watchexec does a cd into the script's directory before running it. That means I can use relative file paths and they'll Just Work™.
What are all those flags?
You can run watchexec from the command line. I like putting it in its own script. That way, I don't have to remember all these incantations:
-
watchexecThe command itself.
-
\The backslash is used to break the overall
watchexeccommand onto multiple lines. It gets used repeatedly. Things are a lot easier to work with that way than if everything was a single line the length of a novel. -
--project-origin .watchexectries to set what it thinks is the root of a project. It causes issues when it gets things wrong. Using the--project-origin .sets it to the current directory explicitly.I don't have a clear enough mental model of
watchexecto know when it's necessary and when it's not. I always throw it in so I don't have to think about it. -
-cClears the screen before every run of the command.
A nice quality of life improvement knowing that you can scroll up and you won't end up looking at the output from a previous run.
-
-rRestarts the target command if it's still running.
Neopolitan's scripts complete so fast this doesn't matter here. It's handy for things like Neopoligen3 that have longer build times.
-
-pPostpone running the target command until the first change is detected.
Without this,
watchexecfires off the target command as soon as it starts. That's fine/desirable in some cases. For this script, that would mean trying to use environmental variables before they are set. -
-e pyTells
watchexecwhat file extensions to watch for changes. In this case that'spyfor my Python files.You can add multiple extensions by separating them with a comma. For example, this would do
.pyand.rsfiles:-e py,rs -
--shell=bashTells
watchexecto to usebashto run the target command. -
--the separator used to package up the command to run as a single argument surrounded by
'characters. -
'The opening single quote. Everything between it and the ending
'constitutes the commandbashruns when files change. -
FILE_PATH="/"This assemble the full path to the target Python script by combining two environmental variables that
watchexecsets:and
It's worth pointing out that there are other environmental variables for file creation, renaming, etc. It would be a little safer to explicitly check to see if
is set. I'll add that if it ever becomes a problem. -
&&The
&&gets used a few times. It makes sure that each part of the command chain only runs if the part before it succeeded. -
PARENT_DIR=""Grabs the parent directory of the target script.
The double quotes nested inside another pair of double quotes always looks weird to me. That's just how bash does it. Without it, you run the risk of file paths wish spaces breaking things in unpredictable ways.
-
Change into the parent directory we just grabbed.
-
python3 "$FILE_PATH"Call
python3with the path to our script stored in$FILE_PATH. This is what actually runs the script. -
'Finally, close the single quote string to finish packaging everything up for
watchexec.
Off And Running
It took half an hour to come up with this script. That's after hours spent figuring out different way to work with watchexec over the years.
I'm happy to trade that time. It allows me to stay in the flow. Plus, I never have to spend that half hour again. I can just grab the script from here whenever I need it. If you end up using it, it'll be even more worth the time spent.
-a
Footnotes
A plain-text file format that's like Markdown on steroids
"a simple, standalone tool that watches a path and runs a command whenever it detects modifications."
Way more complicated than it sounds. Awesome when you learn how to turn it on properly.
The site builder I built that works with Neopolitan files. At the time of this writing it's got a bunch of stuff hard coded to my site. I'm working to remove that so other folks can play with it too.