Skip to content

Instantly share code, notes, and snippets.

@metcalfc
Last active March 12, 2024 21:58
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save metcalfc/a3972c13134cce93ee344d60ce689789 to your computer and use it in GitHub Desktop.
Save metcalfc/a3972c13134cce93ee344d60ce689789 to your computer and use it in GitHub Desktop.
Get a version of Zig for Windows.
<#
.SYNOPSIS
This script downloads and installs the specified version of zig.
.DESCRIPTION
The script downloads the specified version of zig from https://ziglang.org, extracts it into the user's home directory, and optionally adds it to the PATH.
.PARAMETER version
The version of zig to download. If not specified, the script downloads the master version.
.PARAMETER filename
The path to a file containing a JSON object with a "required_zig" field. If specified, the script reads the version from the file.
.PARAMETER updatepath
If specified, the script adds the zig directory to the PATH.
.EXAMPLE
.\ziggy.ps1 -updatepath
.\ziggy.ps1 -version "0.12.0-dev.2741+d7563a775"
.\ziggy.ps1 -filename $HOME\src\ghostty\build.zig
#>
param (
[Parameter(Mandatory=$false)]
[ValidatePattern('^(\d+\.\d+\.\d+)(-dev\.\d+\+\w+)?$')]
[string]$version = "",
[switch]$updatepath = $false,
[Parameter(Mandatory=$false)]
[string]$filename = ""
)
# If a version string is not provided, check the filename
if ($version -eq "") {
if ($filename -ne "") {
$fileContent = Get-Content -Path "$filename" -Raw
try {
$json = ConvertFrom-Json -InputObject $fileContent
$version = $json.version
} catch {
Write-Error "Failed to parse the file content as JSON."
return
}
} else {
$jsonUrl = "https://ziglang.org/download/index.json"
$jsonContent = Invoke-WebRequest -Uri $jsonUrl -UseBasicParsing
$jsonData = ConvertFrom-Json -InputObject $jsonContent.Content
$version = $jsonData.master.version
}
}
# Construct the tarball URL
$tarballUrl = "https://ziglang.org/builds/zig-windows-x86_64-$version.zip"
# Define the path to zig.exe
$zigExePath = "$HOME\zig\zig.exe"
# Check if zig.exe exists
if (Test-Path $zigExePath) {
# Get the output of "zig.exe version"
$zigVersion = & $zigExePath version
# Compare the version string to the output of "zig.exe version"
if ($version -eq $zigVersion) {
Write-Output "The specified version is already installed."
return
}
}
# Download the tarball
$tarballPath = "$HOME\zig.zip"
try {
Invoke-WebRequest -Uri $tarballUrl -OutFile $tarballPath
} catch {
Write-Error "Failed to download the tarball from $tarballUrl"
return
}
# Define the "zig" directory in the user's home directory
$zigDir = "$HOME\zig"
# Check if the "zig" directory exists and remove it if it does
if (Test-Path $zigDir) {
Remove-Item -Path $zigDir -Recurse -Force
}
# Extract the tarball into the "zig" directory
try {
# Exppand-Archive doesn't have the ability to strip components like tar.
# So we need to extract the contents of the tarball into a temporary
# directory and then move the contents to the "zig" directory.
$tempPath = "$HOME\zig\tmp"
Expand-Archive -Path $tarballPath -DestinationPath $tempPath
$contentInsideBogusFolder = Get-Item -Path "$tempPath\zig-windows-*"
Move-Item -Path "$contentInsideBogusFolder\*" -Destination "$HOME\zig" -Force
Remove-Item -Path $tempPath -Recurse -Force
} catch {
Write-Error "Failed to extract the tarball"
return
}
# Clean up the downloaded zip file
Remove-Item -Path $tarballPath -Force
# Check if $updatePath is true
if ($updatePath) {
# Add the "zig" directory to the PATH
$envPath = [Environment]::GetEnvironmentVariable("Path", [EnvironmentVariableTarget]::User)
$newEnvPath = $envPath + ";" + $zigDir
[Environment]::SetEnvironmentVariable("Path", $newEnvPath, [EnvironmentVariableTarget]::User)
# Remind the user to restart their shell
Write-Output "Please restart your shell for the updated PATH to take effect."
}
#!/bin/bash
set -o errexit # abort on nonzero exitstatus
set -o nounset # abort on unbound variable
set -o pipefail # don't hide errors within pipes
ZIG_DOWNLOAD_URL="https://ziglang.org/download/index.json"
ZIG_TMP_FILE=$(mktemp /tmp/zig_version.json.XXXXXX)
ZIG_VERSION=""
FILENAME="" # File name to parse for version
UNINSTALL="false" # Uninstall flag
ZIG_DIR="$HOME/.zig"
BIN_DIR="$HOME/bin"
ZIG_EXE_BIN="$BIN_DIR/zig"
TMP_ZIG_TAR=$(mktemp /tmp/zig.tar.xz.XXXXXX)
OS=""
ARCH=""
check_os_and_arch() {
# Identify the OS
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
OS="linux"
elif [[ "$OSTYPE" == "darwin"* ]]; then
OS="macos"
else
echo "Unsupported operating system. This script works on Linux and macOS."
exit 1
fi
# Identify the architecture
if [[ "$(uname -m)" == "x86_64" ]]; then
ARCH="x86_64"
elif [[ "$(uname -m)" == "arm64" ]]; then
ARCH="aarch64"
else
echo "Unsupported architecture. This script works on x86_64 and ARM."
exit 1
fi
}
# Check if jq, curl, and tar are installed
for cmd in jq curl tar; do
if ! command -v "$cmd" &> /dev/null; then
printf "%s could not be found. Please install it.\n" "$cmd"
exit 1
fi
done
download_file() {
local url="$1"
local dest="$2"
printf "Downloading file from %s...\n" "$url"
curl -sL "$url" -o "$dest"
if [ $? -ne 0 ]; then
printf "Failed to download file from %s\n" "$url"
exit 1
fi
}
check_master() {
# Fetch the latest Zig version
# The latest version of zig is the default without any arguments
download_file $ZIG_DOWNLOAD_URL $ZIG_TMP_FILE
ZIG_VERSION="$(jq -r .master.version $ZIG_TMP_FILE)"
if [ $? -ne 0 ]; then
echo "Failed to parse Zig version info"
exit 1
fi
}
check_file() {
# If FILENAME is set parse it to get the version
if [ -n "$FILENAME" ]; then
if [ -f "$FILENAME" ]; then
echo "Using file: $FILENAME"
ZIG_VERSION=$(cat "$FILENAME" | grep "const required_zig" | cut -d'=' -f2 | tr -d ' ";')
else
echo "File not found: $FILENAME"
exit 1
fi
fi
}
check_install () {
if [ -d "$ZIG_DIR" ]; then
if [ "$( $ZIG_DIR/zig version )" == "$ZIG_VERSION" ]; then
echo "$ZIG_VERSION already installed."
exit 0
else
remove_install
fi
fi
}
install_zig() {
# Download Zig
echo "Downloading Zig version $ZIG_VERSION..."
ZIG_URL="https://ziglang.org/builds/zig-${OS}-${ARCH}-${ZIG_VERSION}.tar.xz"
download_file $ZIG_URL $TMP_ZIG_TAR
# Extract Zig
echo "Extracting Zig..."
mkdir -p "$ZIG_DIR"
if [ $? -ne 0 ]; then
echo "Failed to create directory $ZIG_DIR"
exit 1
fi
tar -xf "$TMP_ZIG_TAR" -C "$ZIG_DIR" --strip-components=1
if [ $? -ne 0 ]; then
echo "Failed to extract Zig"
exit 1
fi
# Add Zig to PATH
echo "Adding Zig to PATH..."
ln -sf "$ZIG_DIR/zig" "$ZIG_EXE_BIN"
if [ $? -ne 0 ]; then
echo "Failed to create symbolic link"
exit 1
fi
}
remove_install () {
# Check if Zig is already installed and remove it
if [ -d "$ZIG_DIR" ]; then
echo "Removing existing Zig installation: $("$ZIG_DIR/zig" version)"
rm -rf "$ZIG_DIR"
fi
}
finish() {
result=$?
rm -f "$TMP_ZIG_TAR"
rm -f "$ZIG_TMP_FILE"
exit ${result}
}
trap finish EXIT ERR
function usage () {
echo "Usage: $0 [options] <file_name>"
echo "Options:"
echo " -b A directory in your PATH to link the Zig binary"
echo " -v Specific version of Zig"
echo " -f Use a different file name"
echo " -u Uninstall Zig"
echo " -h This help"
}
# Parse command line arguments
while getopts ":b:v:f:uh" opt; do
case $opt in
b) BIN_DIR="$OPTARG";;
v) ZIG_VERSION="$OPTARG";;
f) FILENAME="$(realpath "$OPTARG")";;
u) UNINSTALL="true";;
h) usage; exit 0;;
\?) echo "Invalid flag: -$OPTARG"; usage; exit 1;;
esac
done
if [ "$UNINSTALL" == "true" ]; then
echo "Uninstalling zig"
rm -f "$ZIG_EXE_BIN"
remove_install
exit 0
fi
# Check if we need to get the version from a file
if [ -z "$ZIG_VERSION" ] && [ -n "$FILENAME" ]; then
check_file
fi
check_os_and_arch
# Otherwise Check if we need to get the version from the master branch
if [ -z "$ZIG_VERSION" ]; then
check_master
fi
# Check if we've already got the version
check_install
# Download Zig
install_zig
echo "Zig installation complete."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment