Archbootstrap

From ArchWiki
Revision as of 12:20, 30 December 2008 by Tomato (Talk | contribs) (First version of archbootstrap (does not work ATM))

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Tango-view-refresh-red.pngThis article or section is out of date.Tango-view-refresh-red.png

Reason: please use the first argument of the template to provide a brief explanation. (Discuss in Talk:Archbootstrap#)
#!/bin/bash
#########################################################################
# archbootstrap                                                         #
#                                                                       #
# archbootstrap is to archlinux what debootstrap is to Debian.          #
#                                                                       # 
#                                                                       #
# archbootstrap is public domain though i wouldn't mind getting credit. #
#                                                                       #
# by David Leinhäuser (archlinux@calavera.de)                           #
# (minor tweak by lucke)                                                #
#########################################################################


####################
# Default Settings #
####################
MYVERSION="0.3"                              # Version number of this script.
GETCMD="${GETCMD:-wget --passive-ftp -c -q}" # What we use to download files.
PREINSTALL="${PREINSTALL:-glibc iputils}"    # Packages to install before using
                                             # pacman to fetch the rest.
IGNORE="${IGNORE:-}"                         # Packages not to be installed.
TARGET="${1:---help}"                        # Where to bootstrap to
SERVER="${2:-ftp://ftp.archlinux.org}"       # Where to fetch all the files.
INTERACTIVE="${INTERACTIVE:-1}"              # Interactive mode or batch mode

REPOS="current"                              # Which repository to use.
PKG_PACMAN="setup/pacman.pkg.tar.gz"         # Where to find pacman.
PKGLIST="setup/packages.txt"                 # Where to find the packages list.
PKG_PREFIX="base"                            # Install pkgs with this prefix.

####################
# Helper Functions #
####################
PREV_DIR="$(pwd)" # remember current directory so we can chdir back later.

# Print an error message to stderr and quit.
function error() {
	echo "Error: $*" >&2
	cd "${PREV_DIR}"
	exit 1;
}

# Simply exit the script.
function quit() {
	cd "${PREV_DIR}"
	exit 0;
}

# Wrapper around cd for lazy people like me.
function chngdir() {
	cd "$@" || error "chdir failed."
}

#Wrapper around mkdir for lazy people like me.
function makedir() {
	mkdir -p "$@" || error "mkdir failed."
}

#Fetch given URLs into current dir.
function fetch() {
	while [ -n "${1}" ]; do
		if [ -z "${1##file://*}" ]; then
			F="${1#file://}"
			echo "Copying ${F}."
			cp "${1#file://}" . || error "Error copying ${F}."
		else
			echo "Fetching ${1}."
			${GETCMD} "${1}" || error "Error fetching ${1}."
		fi
		shift
	done
}

#Read the package list
PACKAGES=()
function read_pkglist() {
	while read -s; do
		PACKAGES=("${PACKAGES[@]}" "${REPLY}")
	done <"${BOOTSTRAP}/${PKGLIST##*/}"
}

#Return 1 if the first argument does not equal any of the other arguments.
function match() {
	PATTERN="${1}"
	shift
	while [ -n "${1}" ]; do
		[ "${PATTERN}" == "${1}" ] && return 0
		shift
	done
	return 1
}

######################
# Sanity checks etc. #
######################
case "${TARGET}" in
	--help|-h)
		cat <<-EOT
			Usage: $0 DIR [SERVER]
			Bootstrap Archlinux into DIR (from SERVER).
		EOT
		quit;
		;;
	--version)
		echo "archbootstrap ${MYVERSION}";
		quit;
		;;
esac

[ "$UID" == "0" ] || error "You need to be root."

# This is an easy way to get an useful absolute path.
chngdir "${TARGET}"
TARGET="$(pwd)"

#[ -n "$(ls)" ] && error "${1} is not empty."

# Create working directory.
TEMP="${TARGET}/tmp"
makedir -m 1777 -p "${TEMP}"
BOOTSTRAP="${TEMP}/bootstrap"
PKG_CACHE="${TARGET}/var/cache/pacman/pkg"
makedir -m 0755 -p "${BOOTSTRAP}" "${PKG_CACHE}"
chngdir "${BOOTSTRAP}"

########################################
# Stuff we need for our staged install #
########################################
STAGEFILE="${BOOTSTRAP}/stage"
function set_stage() {
	echo "${1}" >"${STAGEFILE}"
	STAGE="${1}"
}

if [ -e "${STAGEFILE}" ]; then
	STAGE="$(< "${STAGEFILE}")"
else
	STAGE="start"
fi

##################
# pacman wrapper #
##################
PACMAN=("$(which chroot)" "${TARGET}" "${BOOTSTRAP#${TARGET}}/usr/bin/pacman.static")
function add_pkgs() {
	PKGS=()
	while [ -n "${1}" ]; do
		PKGS=("${PKGS[@]}" "${1#${TARGET}}")
		shift
	done
	"${PACMAN[@]}" -A "${PKGS[@]}" || error "Could not add a package."
}

function sync_pkgs() {
	if [ "${INTERACTIVE}" == "1" ]; then
		"${PACMAN[@]}" -Syf "${@}" || error "Could not sync a package."
	else
		echo y | "${PACMAN[@]}" -Syf "${@}" || \
			error "Could not sync a package."
	fi
}

#############
# Main loop #
#############
PREV_STAGE=""
FURL="${SERVER}/${REPOS}/os/i686"

echo "archbootstrap $MYVERSION"

until [ "${PREV_STAGE}" == "${STAGE}" ]; do
	PREV_STAGE="${STAGE}"
	case "${STAGE}" in
	start)
		chngdir "${BOOTSTRAP}"
		fetch "${FURL}/${PKG_PACMAN}" "${FURL}/${PKGLIST}"
		tar xfz ${PKG_PACMAN##*/} || \
			error "Could not untar ${BOOTSTRAP}${PKG_PACMAN##*/}."
		makedir "${TARGET}/etc"
		{ echo "[${REPOS}]";
		  echo "Server = ${FURL}"; } >"${TARGET}/etc/pacman.conf" || \
			error "Could not create ${TARGET}/etc/pacman.conf."
		cp -f "/etc/resolv.conf" "${TARGET}/etc/resolv.conf" || \
			error "Could not copy /etc/resolv.conf."
		set_stage "pre_packages"
		;;
	pre_packages)
		chngdir "${PKG_CACHE}"
		[ "${#PACKAGES[@]}" == "0" ] && read_pkglist;
		for I in "${PACKAGES[@]}"; do
			PKGPREFIX="${I%%/*}"
			PKGFILE="${I##*/}"
			PKGNAME="${PKGFILE%-*-*.pkg.tar.gz}"
			if match "${PKGNAME}" ${PREINSTALL}; then
				fetch "${FURL}/${PKGFILE}"
				add_pkgs "${PKG_CACHE}/${PKGFILE}"
			fi
		done
		set_stage "packages"
		;;
	packages)
		chngdir "${BOOTSTRAP}"
		PKGS=()
		[ "${#PACKAGES[@]}" == "0" ] && read_pkglist;
		for I in "${PACKAGES[@]}"; do
			PKGPREFIX="${I%%/*}"
			PKGFILE="${I##*/}"
			PKGNAME="${PKGFILE%-*-*.pkg.tar.gz}"
			[ "${PKGPREFIX}" == "${PKG_PREFIX}" ] || continue
			match "${PKGNAME}" ${IGNORE} ${PREINSTALL} && continue
			PKGS=("${PKGS[@]}" "${PKGNAME}")
		done
		sync_pkgs "${PKGS[@]}"
		set_stage "cleanup"
		;;
	cleanup)
		echo "Cleaning up..."
		chngdir "${TARGET}"
		rm -Rf "${BOOTSTRAP}" || error "Could not remove ${BOOTSTRAP}."
		quit
		;;
	esac
done