Skip to content
This repository has been archived by the owner on Nov 20, 2023. It is now read-only.

Commit

Permalink
feat: ultimate laziness achieved with a powerful new script runner
Browse files Browse the repository at this point in the history
It's so easy that even Homer Simpson could use it to automate the nuclear plant. Enjoy!
  • Loading branch information
Arcitec authored and xynydev committed May 10, 2023
1 parent 55ff636 commit 5cacb2f
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ Instead, you can create shell scripts in the `scripts/` directory (look at the `

Your scripts will be given exactly one argument when they are executed, which specifies its precise execution phase and corresponds to the name of the `scripts:` category that it was assigned to. The primary purpose of this argument is to streamline the reuse of scripts for multiple stages.

If you're looking for a fully automated script runner, you should read the code of the included `scripts/autorun.sh` to see how it works, and then simply specify that as your script in `recipe.yml`. You can also add manually listed scripts in addition to the auto-runner, which can be very useful when managing multiple recipes.

### Custom package repositories

If you want to add custom package repositories to your image, you can include them in the `recipe.yml` as a list of URLs under the `rpm.repos:` section. They **must** be proper `.repo` files (such as `https://copr.fedorainfracloud.org/coprs/atim/starship/repo/fedora-38/atim-starship-fedora-38.repo`). In the build process, the `.repo` file will be downloaded and placed inside `/etc/yum.repos.d/` where rpm-ostree can access it.
Expand Down
9 changes: 9 additions & 0 deletions recipe.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,23 @@ description: A starting point for further customization of uBlue images. Make yo
# Place scripts in the "scripts/" dir and put the corresponding filenames here.
# Any files that aren't listed here won't be executed automatically, which
# means that you can place "helper" or "library" scripts in the folder too.
# Remember to use "autorun.sh" if you want an automatic runner.
scripts:
# "Pre" scripts run very early in the build, immediately after your custom
# repos have been imported (so that you can access those repos if necessary).
pre:
# Automatically runs script files within "scripts/pre/".
- autorun.sh
# Manually listed scripts. Can be combined with the autorunner, which can
# be useful if you're managing multiple recipes and some need extra scripts.
# See the contents of "scripts/autorun.sh" for more usage instructions.
# - example_pre.sh

# "Post" scripts run at the end of the build process.
post:
# Automatically runs script files within "scripts/post/".
- autorun.sh
# Manually listed scripts.
# - example_post.sh

# Custom RPM configuration.
Expand Down
99 changes: 99 additions & 0 deletions scripts/autorun.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#!/usr/bin/env bash

# Tell this script to exit if there are any errors.
set -oue pipefail

#
# AUTORUN:
#
# This script simplifies your "recipe.yml" management whenever you simply want
# to "run everything automatically" based on whatever script files exist on disk.
#
# Set any or all of your "recipe.yml" script categories to "autorun.sh", and
# enjoy the magic! The autorunner will then automatically look up all ".sh"
# script files within the corresponding "scripts/<script mode>/" directory,
# executing them all in their correct alphabetical and numerical filename order.
#
# For example, if you've assigned "autorun.sh" to the "scripts.pre" category
# of your "recipe.yml", then it will scan and automatically execute everything
# in your "scripts/pre/" directory.
#
# There are a few rules, which aim to simplify your script management:
#
# - It will only execute scripts at the FIRST level within the directory, which
# means that anything stored in "scripts/pre/deeperfolder/" will NOT execute.
# This is intentional, so that you can store libraries and helper scripts
# within subdirectories, to simplify your script organization.
#
# - You script directories and the scripts within them can be symlinks, to allow
# easy reuse of scripts. For example, if you want the same scripts to execute
# during both the "pre" and "post" stages, you could simply symlink individual
# scripts or the entire "pre" and "post" directories to each other. However,
# remember to only use RELATIVE symlinks, to ensure that the links work
# properly. For example, "ln -s ../pre/foo.sh scripts/post/foo.sh".
#
# - The scripts will be executed with the name of the current "build execution
# phase" as their first and only argument, to allow you to easily reuse scripts
# across multiple stages. This is consistent with the "build.sh" behavior.
#
# - All scripts execute in a numerically and alphabetically sorted order, which
# allows you to easily control the execution order of your scripts. If it's
# important that they execute in a specific order, then you should give them
# appropriate names. For example, "05-foo.sh" would always execute before
# another script named "99-bar.sh". It's recommended to use zero-padded,
# numerical prefixes when you want to specify the execution order.
#
# - It's possible to mix your "autorun scripts" with your regular "recipe.yml"
# scripts. The autorunner will only execute things from the correctly named
# sub-directories. And the manually listed "recipe.yml" scripts should simply
# be stored directly within "scripts/", or in a custom sub-directory that
# doesn't match any of the "script category" names. For example, you could
# set the "scripts.pre" category of "recipe.yml" to execute both "autorun.sh"
# and "fizzwidget/something.sh", and then place a bunch of auto-executed
# scripts under "scripts/pre/" for the autorunner. This makes it very simple
# to reuse common scripts between multiple different "recipe.yml" files,
# by just placing all commonly shared scripts within auto-runner folders,
# and then manually listing a few specific per-"recipe.yml" scripts within
# each recipe that needs some extra customizations.
#
# - You can safely specify this autorun script as your runner in "recipe.yml",
# even if the corresponding directory doesn't exist or doesn't contain any
# scripts. It will gracefully skip the processing if there's nothing to do.
#

# Helper functions.
yell() { echo "${0}: ${*}"; }
abort() { yell "${*}"; exit 0; }
die() { yell "${*}"; exit 1; }

# Determine which directory and script category we're executing under.
SCRIPT_DIR="$(dirname -- "${BASH_SOURCE[0]}")"
SCRIPT_MODE="${1:-}"
if [[ -z "${SCRIPT_MODE}" ]]; then
die "Missing script mode argument."
fi

# Ensure that a "scripts/" sub-directory exists for the "script category".
# Note that symlinks to other directories will be accepted by the `-d` check.
RUN_DIR="${SCRIPT_DIR}/${SCRIPT_MODE}"
if [[ ! -d "${RUN_DIR}" ]]; then
abort "Nothing to do, since \"${RUN_DIR}\" doesn't exist."
fi

# Generate a numerically sorted array of all scripts (or symlinks to scripts),
# without traversing into deeper subdirectories (to allow the user to store
# helper libraries in subfolders without accidental execution). Sorting is
# necessary for manually controlling the execution order via numeric prefixes.
mapfile -t buildscripts < <(find -L "${RUN_DIR}" -maxdepth 1 -type f -name "*.sh" | sort -n)

# Exit if there aren't any scripts in the directory.
if [[ ${#buildscripts[@]} -eq 0 ]]; then
abort "Nothing to do, since \"${RUN_DIR}\" doesn't contain any scripts in its top-level directory."
fi

# Now simply execute all of the discovered scripts, and provide the name of the
# current "script category" as an argument, to match the behavior of "build.sh".
for script in "${buildscripts[@]}"; do
echo "[autorun.sh] Running [${SCRIPT_MODE}]: ${script}"
"$script" "${SCRIPT_MODE}"
done

0 comments on commit 5cacb2f

Please sign in to comment.