rail5
736313e53e
Rather than relying on the user already owning one, we just go ahead and create one (incl. signing key, etc) This repo can be shipped either as a GitHub Pages site, or via some web server on the host machine, etc. We just create the files This closes #35 and #27
335 lines
11 KiB
Bash
Executable file
335 lines
11 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
|
|
# autobuild setup
|
|
# Copyright (C) 2024 rail5
|
|
# Free software (GNU Affero GPL v3)
|
|
|
|
if [[ "$(whoami)" != _autobuild ]]; then
|
|
echo "Setup must be run via autobuild -s"
|
|
exit 1
|
|
fi
|
|
|
|
local_storage_directory="/var/autobuild"
|
|
autobuild_directory="/usr/share/autobuild"
|
|
CONFIG_FILE="$local_storage_directory/config.toml"
|
|
window_title="Autobuild setup"
|
|
|
|
# Copy any updated files to $local_storage_directory/build-farm in case an upgrade took place
|
|
mkdir -p "$local_storage_directory/build-farm" 2>/dev/null
|
|
cp -ru --preserve=timestamps "${autobuild_directory:?}/build-farm/"* "${local_storage_directory:?}/build-farm/"
|
|
|
|
BUILDFARM_SCRIPTS_FILE="$autobuild_directory/build-farm/scripts/scripts.sh"
|
|
# shellcheck source=./build-farm/scripts/scripts.sh
|
|
. "$BUILDFARM_SCRIPTS_FILE"
|
|
|
|
function setup_single_vm() {
|
|
if [[ $# != 1 ]]; then
|
|
echo "bag args to setup_single_vm" && exit
|
|
fi
|
|
local ARCH="$1"
|
|
|
|
ARCH_DIRECTORY="$local_storage_directory/build-farm/debian-stable-$ARCH"
|
|
cd "$ARCH_DIRECTORY" || (echo ""; echo "Local storage directory is not properly configured"; exit)
|
|
|
|
rm -f "./image.qcow"
|
|
rm -f "./preseed.cfg"
|
|
|
|
cp ../preseed.cfg ./preseed.cfg
|
|
|
|
download_vm_image "$ARCH" "$ARCH_DIRECTORY" 2>/dev/null | dialog --title "$window_title" \
|
|
--progressbox "Downloading $ARCH image... (Please wait)" 15 55
|
|
preseed_vm_image "$ARCH" "$ARCH_DIRECTORY" 2>/dev/null | dialog --title "$window_title" \
|
|
--progressbox "Preparing $ARCH image... (Please wait)" 15 55
|
|
install_vm "$ARCH" "$ARCH_DIRECTORY" 2>/dev/null | dialog --title "$window_title" \
|
|
--progressbox "Installing $ARCH VM... (Please wait, this may take a while)" 15 55
|
|
|
|
rm -f "./"*.iso
|
|
}
|
|
|
|
function setup_build_farm() {
|
|
amd64_vm_is_configured=$(test -f "$local_storage_directory/build-farm/debian-stable-amd64/image.qcow" && echo "true" || echo "false")
|
|
i386_vm_is_configured=$(test -f "$local_storage_directory/build-farm/debian-stable-i386/image.qcow" && echo "true" || echo "false")
|
|
arm64_vm_is_configured=$(test -f "$local_storage_directory/build-farm/debian-stable-arm64/image.qcow" && echo "true" || echo "false")
|
|
|
|
amd64_info_string="Not installed"
|
|
i386_info_string="Not installed"
|
|
arm64_info_string="Not installed"
|
|
|
|
if [[ $amd64_vm_is_configured == true ]]; then
|
|
amd64_info_string="Installed"
|
|
fi
|
|
|
|
if [[ $i386_vm_is_configured == true ]]; then
|
|
i386_info_string="Installed"
|
|
fi
|
|
|
|
if [[ $arm64_vm_is_configured == true ]]; then
|
|
arm64_info_string="Installed"
|
|
fi
|
|
|
|
# --checklist "prompt" width height list_height \
|
|
# "Option Tag" "Option comment" "Status"
|
|
# "Second option name" "Second option comment" "Status"
|
|
# The option is marked with '*' by default if status = "on"
|
|
{ user_choice="$(dialog --title "$window_title" \
|
|
--checklist "Which build farm VMs do you want to install?" 15 55 3 \
|
|
"amd64" "$amd64_info_string" off \
|
|
"i386" "$i386_info_string" off \
|
|
"arm64" "$arm64_info_string" off \
|
|
2>&1 1>&3 3>&- )"; } 3>&1 # Capture stderr output into user_choice variable
|
|
|
|
if [[ "$user_choice" != "" ]]; then
|
|
dialog --title "$window_title" \
|
|
--yesno "Are you sure you want to build VM(s) for $user_choice?\nThis will permanently erase & overwrite the currently-existing VMs for those architectures if they are already installed" 15 55
|
|
|
|
if [[ $? -eq 0 ]]; then
|
|
for choice in $user_choice; do
|
|
setup_single_vm "$choice"
|
|
done
|
|
else
|
|
dialog --title "$window_title" \
|
|
--infobox "Cancelled" 15 55; sleep 3
|
|
fi
|
|
fi
|
|
|
|
}
|
|
|
|
function create_new_debian_repository() {
|
|
# Ask the user for the name and email to use for the package signing key
|
|
local user_email="" user_name="" signing_key_fingerprint="" repo_url="" repo_friendlyname="" default_index_html_code="" repo_will_be_ghpages=false
|
|
{ user_email="$(dialog --title "$window_title" \
|
|
--inputbox "Input the EMAIL to be associated with the package GPG signing key" 15 55 \
|
|
2>&1 1>&3 3>&- )"; } 3>&1
|
|
|
|
echo ""
|
|
echo ""
|
|
echo "$user_email"
|
|
|
|
# Check if we've already made a key with that email
|
|
if gpg --list-secret-keys "$user_email"; then
|
|
key_exists_already=true
|
|
else
|
|
key_exists_already=false
|
|
fi
|
|
use_old_key=$key_exists_already
|
|
|
|
if [[ $key_exists_already == true ]]; then
|
|
dialog --title "$window_title" \
|
|
--yesno "A signing key already exists under '$user_email'.\n\nWould you like to DELETE this one and create a new signing key?" 15 55
|
|
|
|
case $? in
|
|
0)
|
|
use_old_key=false
|
|
;;
|
|
1)
|
|
use_old_key=true
|
|
user_name=$(gpg --with-colons -k "$user_email" | awk -F: '$1=="uid" {print $10}' | sed 's/<.\+>//')
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
if [[ $use_old_key == false ]]; then
|
|
{ user_name="$(dialog --title "$window_title" \
|
|
--inputbox "Input the NAME to be associated with the package GPG signing key" 15 55 \
|
|
2>&1 1>&3 3>&- )"; } 3>&1
|
|
|
|
if [[ $key_exists_already == true ]]; then
|
|
# Delete the old key before creating the new key
|
|
old_fingerprint=$(gpg -K --with-colons "$user_email" | awk -F: '$1=="fpr" {print $10}' | head -n 1)
|
|
gpg --batch --yes --delete-secret-keys "$old_fingerprint"
|
|
gpg --batch --yes --delete-keys "$user_email"
|
|
fi
|
|
|
|
# Create the new key
|
|
gpg --batch --gen-key <<EOF
|
|
%no-protection
|
|
Key-Type:1
|
|
Key-Length:4096
|
|
Subkey-Type:1
|
|
Subkey-Length:4096
|
|
Name-Real: $user_name
|
|
Name-Email: $user_email
|
|
Expire-Date:0
|
|
EOF
|
|
|
|
fi
|
|
|
|
# Get the signing key's fingerprint!
|
|
signing_key_fingerprint=$(gpg -K --with-colons "$user_email" | awk -F: '$1=="fpr" {print $10}' | head -n 1)
|
|
|
|
# Delete any old repository which may or may not exist
|
|
rm -rf "${local_storage_directory:?}/repo/"
|
|
|
|
# Prepare the new repository for reprepro
|
|
mkdir -p "${local_storage_directory:?}/repo/conf"
|
|
cat > "${local_storage_directory:?}/repo/conf/distributions" <<EOF
|
|
Origin: $user_name
|
|
Label: $user_name
|
|
Codename: unstable
|
|
Architectures: source amd64 i386 arm64
|
|
Components: main
|
|
Description: Apt repository for $user_name
|
|
SignWith: $signing_key_fingerprint
|
|
EOF
|
|
|
|
# Ask the user for the repo URL
|
|
{ repo_url="$(dialog --title "$window_title" \
|
|
--inputbox "Input the FULL URL of the Debian Repository\nFor example: https://my.site.com/path/to/repo" 15 55 \
|
|
2>&1 1>&3 3>&- )"; } 3>&1
|
|
|
|
# Get the repo "friendly name":
|
|
## Remove non-alphanumeric characters from the user's name
|
|
## And convert the remainder to lowercase
|
|
# shellcheck disable=SC2001
|
|
repo_friendlyname=$(sed 's/[^A-Za-z0-9\-]//g' <<<"$user_name" | tr '[:upper:]' '[:lower:]')
|
|
|
|
# Export the public key to a file
|
|
gpg --export "$signing_key_fingerprint" > "${local_storage_directory:?}/repo/${repo_friendlyname:?}-signing-key.gpg"
|
|
|
|
# Create the repo .list file
|
|
cat > "${local_storage_directory:?}/repo/${repo_friendlyname:?}.list" <<EOF
|
|
deb $repo_url unstable main
|
|
deb-src $repo_url unstable main
|
|
EOF
|
|
|
|
# Create the default index.html file for the repo
|
|
default_index_html_code=$(cat "${autobuild_directory:?}/repository/default-index.html")
|
|
default_index_html_code="${default_index_html_code//\%REPO_FRIENDLYNAME\%/"$repo_friendlyname"}"
|
|
default_index_html_code="${default_index_html_code//\%REPO_URL\%/"$repo_url"}"
|
|
|
|
cat > "${local_storage_directory:?}/repo/index.html" <<<"$default_index_html_code"
|
|
cp "${autobuild_directory:?}/repository/run_prettify.js" "${local_storage_directory:?}/repo/run_prettify.js"
|
|
|
|
# Will this be some web server, or GitHub Pages?
|
|
# If it's GitHub Pages, we'll have to push changes etc rather than just change files
|
|
dialog --title "$window_title" \
|
|
--yesno "Will this repository be served via GitHub Pages?" 15 55
|
|
|
|
case $? in
|
|
0)
|
|
repo_will_be_ghpages=true
|
|
;;
|
|
1)
|
|
repo_will_be_ghpages=false
|
|
;;
|
|
esac
|
|
|
|
local repo_conf_file="${local_storage_directory:?}/repo/autobuild_repo.conf"
|
|
|
|
echo "[repo]" > "${repo_conf_file:?}"
|
|
|
|
if [[ $repo_will_be_ghpages == true ]]; then
|
|
# Parse autobuild config.toml to get GitHub Credentials
|
|
local config_json=""
|
|
config_json=$(toml2json "$CONFIG_FILE")
|
|
GITHUB_OWNER=$(jq -r ".github.repo_owner" <<<"$config_json")
|
|
GITHUB_EMAIL=$(jq -r ".github.email" <<<"$config_json")
|
|
GITHUB_ACCESS_TOKEN=$(jq -r ".github.access_token" <<<"$config_json")
|
|
|
|
if [[ "$GITHUB_OWNER" == "" || "$GITHUB_EMAIL" == "" || "$GITHUB_ACCESS_TOKEN" == "" ]]; then
|
|
echo "ghpages = false" >> "${repo_conf_file:?}"
|
|
dialog --title "$window_title" \
|
|
--infobox "Error: Your GitHub credentials are not properly configured in /var/autobuild/config.toml\n\nBefore trying again, please ensure that that file contains:\n - Your GitHub username\n - Your GitHub email\n - Your GitHub Access Token" 15 55; sleep 7
|
|
return
|
|
fi
|
|
|
|
echo "ghpages = true" >> "${repo_conf_file:?}"
|
|
|
|
# Ask the user for the Github URL
|
|
{ ghpages_url="$(dialog --title "$window_title" \
|
|
--inputbox "Input the FULL URL of the GitHub Repository that will be used\nFor example: https://github.com/user/repository.git" 15 55 \
|
|
2>&1 1>&3 3>&- )"; } 3>&1
|
|
|
|
echo "ghpages_url = \"$ghpages_url\"" >> "${repo_conf_file:?}"
|
|
|
|
# Initialize the git repo, set origin, and push
|
|
cd "${local_storage_directory:?}/repo" || (echo ""; echo "Confusing and fatal error in setting up GitHub Pages repository"; exit)
|
|
|
|
# Add our necessary credentials to the URL to push (https://user:pass@github.com/etc)
|
|
local push_url="${ghpages_url/:\/\//:\/\/$GITHUB_OWNER:$GITHUB_ACCESS_TOKEN@}"
|
|
|
|
local temporary_repo_changes_directory=""
|
|
temporary_repo_changes_directory=$(mktemp --tmpdir -d)
|
|
mv -f "./"* "${temporary_repo_changes_directory:?}/"
|
|
|
|
git init
|
|
git config user.email "$GITHUB_EMAIL"
|
|
git config user.name "$GITHUB_OWNER"
|
|
git remote add origin "$ghpages_url"
|
|
git pull "$push_url" -q
|
|
|
|
mv -f "${temporary_repo_changes_directory:?}/"* "./"
|
|
rm -rf "${temporary_repo_changes_directory:?}"
|
|
|
|
git add --all
|
|
git commit -m "Initialized Autobuild GitHub Pages Debian Repository"
|
|
git branch -M main
|
|
|
|
git push "$push_url" --all # Push changes
|
|
else
|
|
echo "ghpages = false" >> "${repo_conf_file:?}"
|
|
fi
|
|
|
|
dialog --title "$window_title" \
|
|
--infobox "Your Debian Repo is now configured\n\nYou can check the welcome page at $repo_url\nIf your repo is managed via GitHub Pages, it may take a few moments to publish." 15 55; sleep 7
|
|
}
|
|
|
|
function setup_debian_repo() {
|
|
# First, check: do we have one already?
|
|
debian_repository_already_exists=$(test -f /var/autobuild/repo/autobuild_repo.conf && echo "true" || echo "false")
|
|
|
|
if [[ $debian_repository_already_exists == true ]]; then
|
|
dialog --title "$window_title" \
|
|
--yesno "It looks like a repository already exists in /var/autobuild/repo.\nWould you like to DELETE this repository and create a new one?" 15 55
|
|
|
|
case $? in
|
|
0)
|
|
create_new_debian_repository
|
|
return ;;
|
|
1)
|
|
return ;;
|
|
esac
|
|
else
|
|
create_new_debian_repository
|
|
return
|
|
fi
|
|
}
|
|
|
|
function clear_builds_directory() {
|
|
rm -rf "${local_storage_directory:?}/builds/"*
|
|
dialog --title "$window_title" \
|
|
--infobox "Cleared $local_storage_directory/builds" 15 55; sleep 3
|
|
}
|
|
|
|
function setup_main_menu() {
|
|
{ next_page="$(dialog --title "$window_title" \
|
|
--menu "This menu can be reached anytime with 'autobuild -s'" 15 55 \
|
|
4 \
|
|
1 "Install build farm" \
|
|
2 "Configure Debian Repository" \
|
|
3 "Clear 'builds' directory" \
|
|
4 "Exit" \
|
|
2>&1 1>&3 3>&- )"; } 3>&1 # Capture stderr output into next_page variable
|
|
# 'dialog' writes user responses to stderr
|
|
|
|
case $next_page in
|
|
"" | 4) # User pressed "cancel" or "Exit"
|
|
exit ;;
|
|
1)
|
|
setup_build_farm
|
|
setup_main_menu
|
|
;;
|
|
2)
|
|
setup_debian_repo
|
|
setup_main_menu
|
|
;;
|
|
3)
|
|
clear_builds_directory
|
|
setup_main_menu
|
|
;;
|
|
|
|
esac
|
|
}
|
|
|
|
|
|
setup_main_menu
|