diff --git a/Ports/.port_include.sh b/Ports/.port_include.sh index 32574b0b356..2545272c49c 100755 --- a/Ports/.port_include.sh +++ b/Ports/.port_include.sh @@ -80,6 +80,21 @@ shift : "${workdir:=$port-$version}" +cleanup_git() { + echo "WARNING: Reverting changes to $workdir as we are in dev mode!" + run git clean -xffd >/dev/null 2>&1 +} + +# Use the local git target repo as the workdir +# Make sure to clean it up afterwards +if [ -n "${IN_SERENITY_PORT_DEV:-}" ]; then + echo "WARNING: All changes to the workdir in the current state (inside ./package.sh dev) are temporary!" + echo " They will be reverted once the command exits!" + nongit_workdir="$workdir" + workdir=".$workdir-git" + trap "run cleanup_git" EXIT +fi + run_nocd() { echo "+ $@ (nocd)" >&2 ("$@") @@ -354,7 +369,7 @@ func_defined pre_patch || pre_patch() { func_defined patch_internal || patch_internal() { # patch if it was not yet patched (applying patches multiple times doesn't work!) - if [ -d patches ]; then + if [ -z "${IN_SERENITY_PORT_DEV:-}" ] && [ -d patches ]; then for filepath in patches/*.patch; do filename=$(basename $filepath) if [ ! -f "$workdir"/.${filename}_applied ]; then @@ -386,7 +401,11 @@ func_defined post_install || post_install() { echo } func_defined clean || clean() { - rm -rf "$workdir" *.out + if [ -z "${IN_SERENITY_PORT_DEV:-}" ]; then + rm -rf "$workdir" *.out + else + rm -rf "$nongit_workdir" *.out + fi } func_defined clean_dist || clean_dist() { OLDIFS=$IFS @@ -398,7 +417,11 @@ func_defined clean_dist || clean_dist() { done } func_defined clean_all || clean_all() { - rm -rf "$workdir" *.out + if [ -z "${IN_SERENITY_PORT_DEV:-}" ]; then + rm -rf "$workdir" *.out + else + rm -rf "$nongit_workdir" *.out + fi OLDIFS=$IFS IFS=$'\n' for f in $files; do @@ -551,6 +574,168 @@ do_shell() { echo "End of package shell. Back to the User shell." } +do_generate_patch_readme() { + if [ ! -d patches ]; then + >&2 echo "Error: Port $port does not have any patches" + exit 1 + fi + + if [ -f patches/ReadMe.md ]; then + read -N1 -rp \ + "A ReadMe.md already exists, overwrite? (N/y) " should_overwrite + echo + if [ "${should_overwrite,,}" != y ]; then + >&2 echo "Not overwriting Ports/$port/patches/ReadMe.md" + exit 0 + fi + fi + + rm -fr .patches.tmp + mkdir .patches.tmp + + echo "# Patches for $port on SerenityOS" > patches/ReadMe.md + echo >> patches/ReadMe.md + + pushd patches + + local tempdir="../.patches.tmp" + local count=0 + for patch in *.patch; do + git mailinfo \ + "$tempdir/$patch.msg" \ + /dev/null \ + < "$patch" \ + > "$tempdir/$patch.info" \ + 2> "$tempdir/$patch.error" \ + || { + rc=$? + >&2 echo "Failed to extract patch info from $patch" + >&2 echo "git returned $rc and said:" + >&2 cat "$tempdir/$patch.error" + exit 1 + } + + ( + grep 'Subject: ' "$tempdir/$patch.info" | sed -e 's/Subject: \(.*\)$/\1/' + echo + cat "$tempdir/$patch.msg" + ) > "$tempdir/$patch.desc" + + + if [ ! -s "$tempdir/$patch.desc" ]; then + >&2 echo "WARNING: $patch does not contain a valid git patch or is missing a commit message, and is going to be skipped!" + continue + fi + + { + echo "## \`$patch\`" + echo + cat "$tempdir/$patch.desc" + echo + } >> ReadMe.md + count=$((count + 1)) + done + + popd + + >&2 echo "Successfully generated entries for $count patch(es) in patches/ReadMe.md." +} + +launch_user_shell() { + env \ + IN_SERENITY_PORT_DEV="$port" \ + "${SHELL:-bash}" || \ + true +} + +prompt_yes_no() { + read -N1 -rp \ + "$1 (N/y) " result + 2>&1 echo + if [ "${result,,}" == y ]; then + return 0 + else + return 1 + fi +} + +do_dev() { + if [ -n "${IN_SERENITY_PORT_DEV:-}" ]; then + >&2 echo "Error: Already in dev environment for $IN_SERENITY_PORT_DEV" + exit 1 + fi + + git_repo=".$workdir-git" + [ -d "$git_repo" ] || ( + mv "$workdir" "$git_repo" + pushd "$git_repo" + if [ ! -d "$git_repo/.git" ]; then + git init . + git add . + git commit -a -m 'Initial import' + fi + # Make it allow pushes from other local checkouts + git config receive.denyCurrentBranch ignore + # Import patches as commits, or ask the user to commit them + # if they're not git patches already. + if [ -d ../patches ] && [ -n "$(find ../patches -maxdepth 1 -name '*.patch' -print -quit)" ]; then + for patch in ../patches/*.patch; do + if [ -f "$workdir/.$(basename $patch).applied" ]; then + continue + fi + + echo "Importing patch $patch..." + git am "$patch" || { + git am --abort >/dev/null 2>&1 || true + git apply < $patch || { + # The patch didn't apply, oh no! + # Ask the user to figure it out :shrug: + >&2 echo "- This patch does not apply, you'll be dropped into a shell to investigate and fix this, quit the shell when the problem is resolved." + launch_user_shell + } + git add -A + if prompt_yes_no "- This patch does not appear to be a git patch, would you like to manually commit its changes?"; then + >&2 echo "Apply any changes you want, commit them into the current repo and quit this shell to continue." + + launch_user_shell + else + git commit --verbose + fi + } + done + fi + popd + ) + + [ -d "$git_repo" ] && [ ! -d "$workdir" ] && { + git clone "$git_repo" "$workdir" + } + + [ -d "$workdir/.git" ] || { + >&2 echo "$workdir does not appear to be a git repository, if you did this manually, you're on your own" + if prompt_yes_no "Otherwise, press 'y' to remove that directory and clone it again"; then + rm -fr "$workdir" + git clone "$git_repo" "$workdir" + else + exit 1 + fi + } + + local first_hash="$(git -C "$git_repo" rev-list --max-parents=0 HEAD)" + + launch_user_shell + + local current_hash="$(git -C "$git_repo" rev-parse HEAD)" + + # If the hashes are the same, we have no patches, otherwise generate patches + if [ "$first_hash" != "$current_hash" ]; then + >&2 echo "Note: Regenerating patches as there are some commits in the port repo (started at $first_hash, now is $current_hash)" + rm -fr patches/*.patch + git -C "$git_repo" format-patch "$first_hash" -o "$(realpath patches)" + do_generate_patch_readme + fi +} + NO_GPG=false parse_arguments() { if [ -z "${1:-}" ]; then @@ -558,7 +743,7 @@ parse_arguments() { return fi case "$1" in - fetch|patch|shell|configure|build|install|installdepends|clean|clean_dist|clean_all|uninstall|showproperty) + fetch|patch|shell|configure|build|install|installdepends|clean|clean_dist|clean_all|uninstall|showproperty|generate_patch_readme) method=$1 shift do_${method} "$@" @@ -575,8 +760,21 @@ parse_arguments() { export PS1="(serenity):\w$ " bash --norc ;; + dev) + shift + if [ "${1:-}" != "--no-depends" ]; then + do_installdepends + fi + if [ -d "$workdir" ] && [ ! -d "$workdir/.git" ]; then + if prompt_yes_no "- Would you like to clean the working direcory (i.e. ./package.sh clean)?"; then + do_clean + fi + fi + do_fetch + do_dev + ;; *) - >&2 echo "I don't understand $1! Supported arguments: fetch, patch, configure, build, install, installdepends, interactive, clean, clean_dist, clean_all, uninstall, showproperty." + >&2 echo "I don't understand $1! Supported arguments: fetch, patch, configure, build, install, installdepends, interactive, clean, clean_dist, clean_all, uninstall, showproperty, generate_patch_readme, dev." exit 1 ;; esac