From 472289a641196711f2ae01b6d7b2414ce905553c Mon Sep 17 00:00:00 2001 From: scbj Date: Thu, 11 Jun 2026 13:25:32 +0200 Subject: [PATCH] added bash script developed for computer engineering --- examples/bash/create-students-release.sh | 300 +++++++++++++++++++++++ 1 file changed, 300 insertions(+) create mode 100755 examples/bash/create-students-release.sh diff --git a/examples/bash/create-students-release.sh b/examples/bash/create-students-release.sh new file mode 100755 index 0000000..a510915 --- /dev/null +++ b/examples/bash/create-students-release.sh @@ -0,0 +1,300 @@ +#!/usr/bin/env bash + +### TODO: ensure files deleted in the maintainer repository are +### also deleted in the students repository + +### WARN: this script will not work unless the remote name is `origin` (default). + +### WARN: this script expects you to connect to github via ssh. +### ensure you registered your public key. + +# constant definitions + +# WARN: make sure you understand the implications before +# you change the value (or name) of a constant! + +required_tools=( + "cat" + "dirname" + "find" + "git" + "grep" + "pandoc" + "realpath" + "sed" + "tar" + "tput" +) +common_dir="../common" +laboratory_dir="./laboratories" +student_repo_name="student-repository" +student_repo_url="git@github.zhaw.ch:CT/ct1-students.git" +code_start="STUDENTS: To be programmed" +code_end="END: To be programmed" +make_start="solution[s]*=start" +make_end="solution[s]*=end" +md_solution_start="solution[s]*=start" +md_solution_end="solution[s]*=end" +md_student_start="student[s]*=start" +md_student_end="student[s]*=end" +keili_dir_name="keil" +archive_name="release.tar" +exclude_file_name=".release-ignore" + +# sanity checks for variables +if [[ "${laboratory_dir}" =~ ".." ]]; then + echo "'laboratory_dir' has to be a child directory of the one containing this script" +fi +if [[ "." != "$(dirname "${student_repo_name}")" ]]; then + echo "'student_repo_name' may not contain directories!" + exit 0 +fi +if [[ "." != "$(dirname "${keili_dir_name}")" ]]; then + echo "'keili_dir_name' may not contain directories!" + exit 0 +fi +if [[ "." != "$(dirname "${exclude_file_name}")" ]]; then + echo "'exclude_file_name' may not contain directories!" + exit 0 +fi + +# helper function declarations + +## print highlighted text +## +## used the same as `echo` +function print_highlighted { + if ! $(which tput &>/dev/null) || [[ -z "$(tput smso)" ]]; then + echo "$*" + return 0 + fi + + tput smso + echo "$*" + tput sgr0 +} + +## print yellow text +## +## used the same as `echo` +function print_warning { + if ! $(which tput &>/dev/null); then + echo "$*" + return 0 + fi + + tput setaf 3 + echo "$*" + tput sgr0 +} + +## print red text +## +## used the same as `echo` +function print_error { + if ! $(which tput &>/dev/null); then + echo "$*" + return 0 + fi + + tput setaf 1 + echo "$*" + tput sgr0 +} + +# main logic + +# ensure the required tools are available +unset error_message +for tool in "${required_tools}"; do + if ! $(which "${tool}" &>/dev/null); then + error_message+="${tool}" + fi +done +if [[ -n "${error_message}" ]]; then + print_error "missing the following tools: [ ${error_message} ]" + exit 1 +fi + +# ensure commands are executed in the directory where the +# script is located +root_dir="$(realpath "${BASH_SOURCE}" | dirname -)" +cd "${root_dir}" + +# check that there are no paths with spaces +illegal_paths="$(find . -type d -name ".git" -prune -o -name "*" -print | + sort | grep ' ')" +if [[ -n "${illegal_paths}" ]]; then + print_error "no spaces in paths allowed!" + print_error "the following paths are illegal:" + echo "" + echo "${illegal_paths}" + exit 1 +fi + +# ensure the working tree of the maintainer repository is not behind +# no need to check the students repository, as it is derived from the +# maintainer repository +git fetch &>/dev/null +if [[ -n "$(git diff origin/HEAD)" ]]; then + print_warning "working tree of the maintainer repository differs from the remotes head." + print_warning "pull and/or commit/push first to resolve the differences." + exit 1 +fi + +# remove trailing whitespace and convert to unix file format +bash "${common_dir}/trailing-whitespace.sh" -u . + +# ensure the students repository is checked out +if [[ ! -d "${student_repo_name}" ]]; then + print_highlighted "cloning students repository" + git clone "${student_repo_url}" "${student_repo_name}" +fi + +# ensure the students repository is ignored +if [[ -z "$(cat "./.gitignore" | grep "${student_repo_name}")" ]]; then + echo "${student_repo_name}/" >>"./.gitignore" +fi + +# remove solutions from source code +code_files=($( + find "${laboratory_dir}" \ + -type f \ + -name "*.[chs]" +)) + +for file in "${code_files[@]}"; do + sed -i " + /${code_start}/,/${code_end}/ { + /${code_start}/n + /${code_end}/!d + }" ${file} + + # add blank lines to show where code goes + sed -i "/${code_start}/a\\\\" ${file} + sed -i "/${code_start}/a\\\\" ${file} + sed -i "/${code_start}/a\\\\" ${file} +done + +echo "> removed solutions from source files." + +# removing solutions from makefiles +make_files=($( + find "${laboratory_dir}" \ + -type f \ + -name "Makefile" \ + -or \ + -name "*.mk" +)) + +for file in "${make_files[@]}"; do + sed -i "/${make_start}/,/${make_end}/d" ${file} +done + +# remove solutions from lab instructions +md_files=($( + find "${laboratory_dir}" \ + -type f \ + -name "*.md" +)) + +for file in "${md_files[@]}"; do + sed -i "/${md_solution_start}/,/${md_solution_end}/d" ${file} + sed -i "/${md_student_start}/d" ${file} + sed -i "/${md_student_end}/d" ${file} +done + +echo "> removed solutions from lab instructions." + +# convert readmes from `pandoc markdown` to `github flavoured markdown` and pdf +echo "converting markdown files to pdfs" +echo "(this may take a while)" + +template="$(realpath "${common_dir}/template.tex")" +unset pdf_files +for file in "${md_files[@]}"; do + filename="${file##*/}" + pushd "${file%/*}" &>/dev/null + pandoc \ + -f markdown \ + -t pdf \ + --pdf-engine pdflatex \ + --listings \ + --template "${template}" \ + "${filename}" \ + -o "${filename/%md/pdf}" + pandoc \ + -f markdown \ + -t gfm \ + "${filename}" \ + -o "${filename}" + popd &>/dev/null + pdf_files+=("${file/%md/pdf}") +done +unset template + +echo "> converted readme files to github flavoured markdown." + +# generate zip archives of keili projects +keili_dirs=($(find . -type d -name "${keili_dir_name}")) +for item in "${keili_dirs[@]}"; do + pushd "$(dirname "${item}")" &>/dev/null + zip -r "${keili_dir_name}.zip" "${keili_dir_name}" &>/dev/null + popd &>/dev/null +done +unset keili_dirs + +keili_archives=($(find "${laboratory_dir}" -name "${keili_dir_name}.zip")) + +# copy modified contents to students repository +exclude_patterns=("${exclude_file_name}") +exclude_patterns+=("${keili_dir_name}") +exclude_patterns+=("*.pptx") +exclude_patterns+=("*.docx") + +# collect exclude globs +ignore_files=($(find . -type f -iname "${exclude_file_name}")) +for file in "${ignore_files[@]}"; do + temp_path="$(dirname ${file})/" + temp_patterns=($(cat "${file}")) + exclude_patterns+=(${temp_patterns[@]/#/${temp_path}}) +done + +# remove contents of the student repository to avoid +# orphaned files/directories +find "${student_repo_name}" \ + -mindepth 1 \ + -maxdepth 1 \ + -not -name ".git" \ + -exec rm -rf {} \; + +# create release using `tar` +tar -cf "${archive_name}" \ + -h \ + --exclude-vcs \ + --exclude-vcs-ignore \ + --exclude="${archive_name}" \ + "${exclude_patterns[@]/#/--exclude=}" \ + "${keili_archives[@]/#/--add-file=}" \ + "${pdf_files[@]/#/--add-file=}" \ + . +tar -xf "${archive_name}" \ + -C "${student_repo_name}/" + +# reset repository after release creation +git reset --hard &>/dev/null +git clean -fd &>/dev/null +rm "${keili_archives[@]}" "${pdf_files[@]}" + +# print message to report success and a reminder to commit and +# push the students repository +relative_path="$(dirname "${BASH_SOURCE}")/${student_repo_name}" + +echo "" +echo "successfully prepared the release for the students repository." +echo "generated release is found at \`${relative_path}\`." +echo "" + +print_highlighted "remember to commit and push the generated release!" + +echo ""