Creating An Install Script For Marmite A Step-by-Step Guide
Hey guys! Today, we're diving into creating an install script for Marmite, making it super easy for everyone to get started. This is going to be a game-changer for new users, allowing them to install Marmite with just a single command. Let's break down the process step by step.
Understanding the Goal
The main goal here is to create a script that automatically detects the user's operating system and architecture, fetches the correct Marmite binary from the latest release, and installs it in the appropriate directory. This script will be served at https://marmite.blog/install.sh
, making it accessible to anyone.
Why an Install Script?
Having an install script simplifies the installation process significantly. Instead of manually downloading and configuring Marmite, users can simply run a single command. This reduces friction and makes it more likely that people will try out Marmite. Plus, it's just cool!
Step-by-Step Implementation
Let’s walk through the steps required to create this awesome install script.
1. Script Location and Setup
First things first, we need to set up the script within our project. We'll start by adding an install.sh
script to the example/scripts/
directory. This keeps our project organized and ensures the script is version-controlled.
mkdir -p example/scripts
touch example/scripts/install.sh
chmod +x example/scripts/install.sh
Next, we need to tell Marmite to serve this script. We'll add a file mapping in .github/marmite.yaml
that points scripts/install.sh
to install.sh
. This ensures that the script is accessible via the https://marmite.blog/install.sh
URL.
file_mappings:
- source: scripts/install.sh
destination: install.sh
2. Gathering System Information
The install script needs to know the user's operating system (Linux, Windows, macOS) and architecture (x86_64, aarch64, etc.) to download the correct binary. We can use standard shell commands to gather this information.
#!/bin/bash
os=$(uname -s)
arch=$(uname -m)
echo "Detected OS: $os"
echo "Detected Architecture: $arch"
This snippet uses uname -s
to get the operating system and uname -m
to get the architecture. It's super important to handle different cases and variations in these outputs to ensure the script works reliably across various systems.
3. Fetching the Latest Release Information
To download the correct Marmite binary, the install script needs to fetch the latest release information from the GitHub API. We can use curl
to make a request to https://api.github.com/repos/rochacbruno/marmite/releases/latest
.
release_info=$(curl -sS https://api.github.com/repos/rochacbruno/marmite/releases/latest)
echo "Fetched release info: $release_info"
This command fetches the JSON response containing the release information. We'll need to parse this JSON to extract the asset URLs.
4. Parsing JSON and Finding the Correct Artifact
Parsing JSON in shell scripts can be a bit tricky, but tools like jq
make it much easier. We'll use jq
to extract the assets
array from the JSON response and then iterate through them to find a matching artifact based on the OS and architecture.
if ! command -v jq &> /dev/null;
then
echo "jq is required to parse JSON. Please install it."
exit 1
fi
assets=$(echo "$release_info" | jq -r '.assets')
for asset in $(echo "$assets" | jq -r '.[] | @base64'); do
asset_decoded=$(echo "$asset" | base64 --decode)
name=$(echo "$asset_decoded" | jq -r '.name')
browser_download_url=$(echo "$asset_decoded" | jq -r '.browser_download_url')
if [[ "$name" == *"$os"* && "$name" == *"$arch"* ]]; then
echo "Found matching artifact: $name"
download_url=$browser_download_url
break
fi
done
if [ -z "$download_url" ]; then
echo "No matching artifact found for OS: $os and Architecture: $arch"
exit 1
fi
echo "Download URL: $download_url"
This snippet first checks if jq
is installed and exits if it's not. Then, it iterates through the assets, decodes the base64 encoded JSON, and checks if the asset name matches the detected OS and architecture. If a match is found, it stores the download URL and breaks the loop.
5. Downloading the Artifact
With the download URL in hand, we can use curl
to download the artifact. We'll also use wget
as a fallback in case curl
is not available.
download_file() {
url=$1
output_file=$2
if command -v curl &> /dev/null; then
curl -sSLo "$output_file" "$url"
elif command -v wget &> /dev/null; then
wget -q -O "$output_file" "$url"
else
echo "curl or wget is required to download the artifact. Please install one of them."
exit 1
fi
}
filename=$(basename "$download_url")
download_file "$download_url" "$filename"
echo "Downloaded: $filename"
This function download_file
downloads the artifact using curl
or wget
, handling cases where neither is available. It’s crucial to provide clear error messages to the user if dependencies are missing.
6. Unpacking the Binary
Once the artifact is downloaded, we need to unpack it. The script needs to handle different archive types (tar.gz, zip, etc.).
unpack_archive() {
archive=$1
if [[ "$archive" == *.tar.gz ]]; then
tar -xzf "$archive"
elif [[ "$archive" == *.zip ]]; then
unzip "$archive"
else
echo "Unsupported archive type: $archive"
exit 1
fi
}
unpack_archive "$filename"
echo "Unpacked: $filename"
This function unpack_archive
checks the file extension and uses the appropriate command to unpack the archive. It’s essential to support all archive types that Marmite releases might use.
7. Installing the Binary
After unpacking, the script needs to move the marmite
binary to a suitable location. We'll try to install it in the user's default binary directory (~/.local/bin
) or any other discoverable directory. If that fails, we'll write the file to the current running folder.
install_binary() {
binary_name=marmite
if [ -d "$HOME/.local/bin" ]; then
install_dir="$HOME/.local/bin"
elif command -v brew &> /dev/null && [ -d "$(brew --prefix)/bin" ]; then
install_dir="$(brew --prefix)/bin"
else
install_dir="."
fi
cp "$binary_name" "$install_dir"
if [ "$install_dir" != "." ]; then
echo "Installed marmite to $install_dir"
else
echo "Failed to install to standard locations, installed to current directory."
fi
if [ "$install_dir" != "." ]; then
chmod +x "$install_dir/$binary_name"
else
chmod +x "./$binary_name"
fi
}
install_binary
This function install_binary
first determines the installation directory, then copies the binary, and sets execute permissions. It's important to inform the user if the installation fails to a standard location.
8. Warning the User About PATH
Finally, the script should warn the user about ensuring the installation location is in their PATH
environment variable.
echo "Please ensure $install_dir is in your PATH."
This is crucial because the user needs to be able to run marmite
from any terminal location.
Complete Install Script
Here's the complete install.sh
script:
#!/bin/bash
os=$(uname -s)
arch=$(uname -m)
echo "Detected OS: $os"
echo "Detected Architecture: $arch"
if ! command -v jq &> /dev/null;
then
echo "jq is required to parse JSON. Please install it."
exit 1
fi
release_info=$(curl -sS https://api.github.com/repos/rochacbruno/marmite/releases/latest)
assets=$(echo "$release_info" | jq -r '.assets')
for asset in $(echo "$assets" | jq -r '.[] | @base64'); do
asset_decoded=$(echo "$asset" | base64 --decode)
name=$(echo "$asset_decoded" | jq -r '.name')
browser_download_url=$(echo "$asset_decoded" | jq -r '.browser_download_url')
if [[ "$name" == *"$os"* && "$name" == *"$arch"* ]]; then
echo "Found matching artifact: $name"
download_url=$browser_download_url
break
fi
done
if [ -z "$download_url" ]; then
echo "No matching artifact found for OS: $os and Architecture: $arch"
exit 1
fi
echo "Download URL: $download_url"
download_file() {
url=$1
output_file=$2
if command -v curl &> /dev/null; then
curl -sSLo "$output_file" "$url"
elif command -v wget &> /dev/null; then
wget -q -O "$output_file" "$url"
else
echo "curl or wget is required to download the artifact. Please install one of them."
exit 1
fi
}
filename=$(basename "$download_url")
download_file "$download_url" "$filename"
echo "Downloaded: $filename"
unpack_archive() {
archive=$1
if [[ "$archive" == *.tar.gz ]]; then
tar -xzf "$archive"
elif [[ "$archive" == *.zip ]]; then
unzip "$archive"
else
echo "Unsupported archive type: $archive"
exit 1
fi
}
unpack_archive "$filename"
echo "Unpacked: $filename"
install_binary() {
binary_name=marmite
if [ -d "$HOME/.local/bin" ]; then
install_dir="$HOME/.local/bin"
elif command -v brew &> /dev/null && [ -d "$(brew --prefix)/bin" ]; then
install_dir="$(brew --prefix)/bin"
else
install_dir="."
fi
cp "$binary_name" "$install_dir"
if [ "$install_dir" != "." ]; then
echo "Installed marmite to $install_dir"
else
echo "Failed to install to standard locations, installed to current directory."
fi
if [ "$install_dir" != "." ]; then
chmod +x "$install_dir/$binary_name"
else
chmod +x "./$binary_name"
fi
}
install_binary
echo "Please ensure $install_dir is in your PATH."
9. Testing the Script
Before deploying, it's crucial to test the script thoroughly on different platforms and architectures. You can use virtual machines or cloud instances to simulate various environments.
10. Adding Command-Line Options
To make the install script more flexible, we can add command-line options. For example, users might want to specify a custom installation directory. We can use getopts
to parse command-line arguments.
while getopts d: option
do
case "$option" in
d)
custom_bin_dir="$OPTARG"
;;
\?)
echo "Usage: $0 [-d install_directory]"
exit 1
;;
esac
done
if [ -n "$custom_bin_dir" ]; then
install_dir="$custom_bin_dir"
fi
echo "Installing to: $install_dir"
This snippet allows users to specify an installation directory using the -d
option. It’s super useful for advanced users who have specific directory preferences.
Usage Instructions
Users can now install Marmite using the following command:
curl -sS https://marmite.blog/install.sh | sh
Or, to specify a custom installation directory:
curl -sS https://marmite.blog/install.sh | sh -s -- --bin-dir /custom/bin/folder
Follow-Up Tasks
To ensure the new installation method is well-documented and promoted, we need to complete a few follow-up tasks.
1. Update Installation Documentation
Create a new Markdown file in the example/content/
directory (e.g., DATE-installation.md
) explaining all existing installation methods, including the new script. Clear documentation is key to user adoption.
2. Copy Hero File
Copy the hero file from example/content/_hero.md
to .github/_hero.md
to customize the landing page.
cp example/content/_hero.md .github/_hero.md
3. Edit Hero File
Edit .github/_hero.md
to add a quick start section that includes the new installation command. This makes it easy for new users to get started.
## Quick Start
### Install
`curl -sS https://marmite.blog/install.sh | sh` or [Click Here for more install options](link-to-installation-docs)
### Create a blog
marmite myblog --init-site
--name Mysite
--tagline "My Articles and Notes"
--colorscheme nord
--toc true
--enable-search true
### Write a post
marmite myblog --new "My First Blog Post" -t "new,post"
### Serve the blog
marmite myblog --serve --watch
4. Update GitHub Actions Workflow
Edit .github/main.yml
to copy the hero file to the Marmite site during the preparation step. This ensures the landing page is updated with the new installation instructions.
- name: Prepare Site
run: |
mkdir -p marmitesite/content
cp example/content/* marmitesite/content/
cp .github/_hero.md marmitesite/content/_hero.md
Conclusion
Creating an install script for Marmite is a significant step towards improving the user experience. By automating the installation process, we make it easier for new users to get started and explore the tool. Remember, thorough testing and clear documentation are crucial for success. So, let's get this script out there and make Marmite even more accessible!
By following these steps, we've created a robust and user-friendly installation script for Marmite. This not only simplifies the installation process but also makes Marmite more accessible to a wider audience. Keep up the great work, guys!