add script for managing 'build environments' (.config+files/), including documentation
SVN-Revision: 12212
This commit is contained in:
		| @@ -483,3 +483,60 @@ Other useful targets include: | ||||
|     \item \texttt{make package/\textit{<name>}/configure V=99} | ||||
| \end{itemize} | ||||
|  | ||||
|  | ||||
| \subsection{Using build environments} | ||||
| OpenWrt provides a means of building images for multiple configurations | ||||
| which can use multiple targets in one single checkout. These \emph{environments} | ||||
| store a copy of the .config file generated by \texttt{make menuconfig} and the contents | ||||
| of the \texttt{./files} folder. | ||||
| The script \texttt{./scripts/env} is used to manage these environments, it uses | ||||
| \texttt{git} (which needs to be installed on your system) as backend for version control. | ||||
|  | ||||
| The command  | ||||
| \begin{Verbatim} | ||||
|   \texttt{./scripts/env help} | ||||
| \end{Verbatim} | ||||
| produces a short help text with a list of commands. | ||||
|  | ||||
| To create a new environment named \texttt{current}, run the following command | ||||
| \begin{Verbatim} | ||||
|   ./scripts/env new current | ||||
| \end{Verbatim} | ||||
| This will move your \texttt{.config} file and \texttt{./files} (if it exists) to | ||||
| the \texttt{env/} subdirectory and create symlinks in the base folder. | ||||
|  | ||||
| After running make menuconfig or changing things in files/, your current state will | ||||
| differ from what has been saved before. To show these changes, use: | ||||
| \begin{Verbatim} | ||||
|   ./scripts/env diff | ||||
| \end{Verbatim} | ||||
|  | ||||
| If you want to save these changes, run: | ||||
| \begin{Verbatim} | ||||
|   ./scripts/env save | ||||
| \end{Verbatim} | ||||
| If you want to revert your changes to the previously saved copy, run: | ||||
| \begin{Verbatim} | ||||
|   ./scripts/env revert | ||||
| \end{Verbatim} | ||||
|  | ||||
| If you want, you can now create a second environment using the \texttt{new} command. | ||||
| It will ask you whether you want to make it a clone of the current environment (e.g. | ||||
| for minor changes) or if you want to start with a clean version (e.g. for selecting | ||||
| a new target). | ||||
|  | ||||
| To switch to a different environment (e.g. \texttt{test1}), use: | ||||
| \begin{Verbatim} | ||||
|   ./scripts/env switch test1 | ||||
| \end{Verbatim} | ||||
|  | ||||
| To rename the current branch to a new name (e.g. \texttt{test2}), use: | ||||
| \begin{Verbatim} | ||||
|   ./scripts/env rename test2 | ||||
| \end{Verbatim} | ||||
|  | ||||
| If you want to get rid of environment switching and keep everything in the base directory | ||||
| again, use: | ||||
| \begin{Verbatim} | ||||
|   ./scripts/env clear | ||||
| \end{Verbatim} | ||||
|   | ||||
							
								
								
									
										219
									
								
								scripts/env
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										219
									
								
								scripts/env
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,219 @@ | ||||
| #!/usr/bin/env bash | ||||
| BASEDIR="$PWD" | ||||
| ENVDIR="$PWD/env" | ||||
|  | ||||
| usage() { | ||||
| 	cat <<EOF | ||||
| Usage: $0 [options] <command> [arguments] | ||||
| Commands: | ||||
| 	help              This help text | ||||
| 	list              List environments | ||||
| 	clear             Delete all environment and revert to flat config/files | ||||
| 	new <name>        Create a new environment | ||||
| 	switch <name>     Switch to a different environment | ||||
| 	delete <name>     Delete an environment | ||||
| 	rename <newname>  Rename the current environment | ||||
| 	diff              Show differences between current state and environment | ||||
| 	save              Save your changes to the environment | ||||
| 	revert            Revert your changes since last save | ||||
|  | ||||
| Options: | ||||
|  | ||||
| EOF | ||||
| 	exit ${1:-1} | ||||
| } | ||||
|  | ||||
| error() { | ||||
| 	echo "$0: $*" | ||||
| 	exit 1 | ||||
| } | ||||
|  | ||||
| ask_bool() { | ||||
| 	local DEFAULT="$1"; shift | ||||
| 	local def defstr val | ||||
| 	case "$DEFAULT" in | ||||
| 		1) def=0; defstr="Y/n";; | ||||
| 		0) def=1; defstr="y/N";; | ||||
| 		*) def=;  defstr="y/n";; | ||||
| 	esac | ||||
| 	while [ -z "$val" ]; do | ||||
| 		local VAL | ||||
|  | ||||
| 		echo -n "$* ($defstr): " | ||||
| 		read VAL | ||||
| 		case "$VAL" in | ||||
| 			y*|Y*) val=0;; | ||||
| 			n*|N*) val=1;; | ||||
| 			*) val="$def";; | ||||
| 		esac | ||||
| 	done | ||||
| 	return "$val" | ||||
| } | ||||
|  | ||||
| env_init() { | ||||
| 	local CREATE="$1" | ||||
| 	if [ -z "$CREATE" ]; then | ||||
| 		[ -d "$ENVDIR" ] || exit 0 | ||||
| 	fi | ||||
| 	[ -x "$(which git 2>/dev/null)" ] || error "Git is not installed" | ||||
| 	mkdir -p "$ENVDIR" || error "Failed to create the environment directory" | ||||
| 	cd "$ENVDIR" || error "Failed to switch to the environment directory" | ||||
| 	[ -d .git ] || {  | ||||
| 		git init && | ||||
| 		touch .config && | ||||
| 		mkdir files && | ||||
| 		git-add . &&  | ||||
| 		git-commit -q -m "Initial import" | ||||
| 	} || { | ||||
| 		rm -rf .git | ||||
| 		error "Failed to initialize the environment directory" | ||||
| 	} | ||||
| } | ||||
|  | ||||
| env_sync_data() { | ||||
| 	[ \! -L "$BASEDIR/.config" -a -f "$BASEDIR/.config" ] && mv "$BASEDIR/.config" "$ENVDIR" | ||||
| 	git-add . | ||||
| 	git-add -u | ||||
| } | ||||
|  | ||||
| env_sync() { | ||||
| 	local STR="$1" | ||||
| 	env_sync_data | ||||
| 	git-commit -m "${STR:-Update} at $(date)" | ||||
| } | ||||
|  | ||||
| env_link_config() { | ||||
| 	rm -f "$BASEDIR/.config" | ||||
| 	ln -s env/.config "$BASEDIR/.config" | ||||
| 	mkdir -p "$ENVDIR/files" | ||||
| 	[ -L "$BASEDIR/files" ] || ln -s env/files "$BASEDIR/files" | ||||
| } | ||||
|  | ||||
| env_do_reset() { | ||||
| 	git-reset --hard HEAD | ||||
| 	git-clean -d -f | ||||
| } | ||||
|  | ||||
| env_list() { | ||||
| 	env_init | ||||
| 	git-branch | grep -vE '^. master$' | ||||
| } | ||||
|  | ||||
| env_diff() { | ||||
| 	env_init | ||||
| 	env_sync_data | ||||
| 	git-diff --cached | ||||
| } | ||||
|  | ||||
| env_save() { | ||||
| 	env_init | ||||
| 	env_sync | ||||
| 	env_link_config | ||||
| } | ||||
|  | ||||
| env_revert() { | ||||
| 	env_init | ||||
| 	env_do_reset | ||||
| 	env_link_config | ||||
| } | ||||
|  | ||||
| env_ask_sync() { | ||||
| 	LINES="$(env_diff | wc -l)" # implies env_init | ||||
| 	[ "$LINES" -gt 0 ] && { | ||||
| 		if ask_bool 1 "Do you want to save your changes"; then | ||||
| 			env_sync | ||||
| 		else | ||||
| 			env_sync_data | ||||
| 			env_do_reset | ||||
| 		fi | ||||
| 	} | ||||
| } | ||||
|  | ||||
| env_clear() { | ||||
| 	env_init | ||||
| 	[ -L "$BASEDIR/.config" ] && rm -f "$BASEDIR/.config" | ||||
| 	[ -L "$BASEDIR/files" ] && rm -f "$BASEDIR/files" | ||||
| 	[ -f "$ENVDIR/.config" ] || ( cd "$ENVDIR/files" && find | grep -vE '^\.$' > /dev/null ) | ||||
| 	env_sync_data | ||||
| 	if ask_bool 1 "Do you want to keep your current config and files"; then | ||||
| 		mkdir -p "$BASEDIR/files" | ||||
| 		cp -a "$ENVDIR/files/*" "$BASEDIR/files" 2>/dev/null >/dev/null | ||||
| 		cp "$ENVDIR/.config" "$BASEDIR/" | ||||
| 	else | ||||
| 		rm -rf "$BASEDIR/files" "$BASEDIR/.config" | ||||
| 	fi | ||||
| 	cd "$BASEDIR" | ||||
| 	rm -rf "$ENVDIR" | ||||
| } | ||||
|  | ||||
| env_delete() { | ||||
| 	local name="${1##*/}" | ||||
| 	[ -z "$name" ] && usage | ||||
| 	[ -f "$envdir/.git/refs/heads/$name" ] || error "environment '$name' not found" | ||||
| 	branch="$(git-branch | grep '^\* ' | awk '{print $2}')" | ||||
| 	[ "$name" = "branch" ] && error "cannot delete the currently selected environment" | ||||
| 	git-branch -D "$name" | ||||
| } | ||||
|  | ||||
| env_switch() { | ||||
| 	local name="${1##*/}" | ||||
| 	[ -z "$name" ] && usage | ||||
| 	[ -f "$envdir/.git/refs/heads/$name" ] || error "environment '$name' not found" | ||||
|  | ||||
| 	env_init | ||||
| 	env_ask_sync | ||||
| 	git-checkout "$NAME" | ||||
| 	env_link_config | ||||
| } | ||||
|  | ||||
| env_rename() { | ||||
| 	local NAME="${1##*/}" | ||||
| 	env_init | ||||
| 	git-branch -m "$NAME" | ||||
| } | ||||
|  | ||||
| env_new() { | ||||
| 	local NAME="$1" | ||||
| 	local branch | ||||
| 	local from="master" | ||||
|  | ||||
| 	[ -z "$NAME" ] && usage | ||||
| 	env_init 1 | ||||
| 	 | ||||
| 	branch="$(git-branch | grep '^\* ' | awk '{print $2}')" | ||||
| 	if [ -n "$branch" -a "$branch" != "master" ]; then | ||||
| 		env_ask_sync | ||||
| 		if ask_bool 0 "Do you want to clone the current environment?"; then | ||||
| 			from="$branch" | ||||
| 		fi | ||||
| 		rm -f "$BASEDIR/.config" "$BASEDIR/files" | ||||
| 	fi | ||||
| 	git-checkout -b "$1" "$from" | ||||
| 	if [ -f "$BASEDIR/.config" -o -d "$BASEDIR/files" ]; then | ||||
| 		if ask_bool 1 "Do you want to keep your current config and files?"; then | ||||
| 			[ -d "$BASEDIR/files" -a \! -L "$BASEDIR/files" ] && { | ||||
| 				mv "$BASEDIR/files/"* "$ENVDIR/" 2>/dev/null | ||||
| 				rmdir "$BASEDIR/files" | ||||
| 			} | ||||
| 			env_sync | ||||
| 		else | ||||
| 			rm -rf "$BASEDIR/.config" "$BASEDIR/files" | ||||
| 		fi | ||||
| 	fi | ||||
| 	env_link_config | ||||
| } | ||||
|  | ||||
| COMMAND="$1"; shift | ||||
| case "$COMMAND" in | ||||
| 	help) usage 0;; | ||||
| 	new) env_new "$@";; | ||||
| 	list) env_list "$@";; | ||||
| 	clear) env_clear "$@";; | ||||
| 	switch) env_switch "$@";; | ||||
| 	delete) env_delete "$@";; | ||||
| 	rename) env_rename "$@";; | ||||
| 	diff) env_diff "$@";; | ||||
| 	save) env_save "$@";; | ||||
| 	revert) env_revert "$@";; | ||||
| 	*) usage;; | ||||
| esac | ||||
		Reference in New Issue
	
	Block a user
	 Felix Fietkau
					Felix Fietkau