From dc418add8e1d164e512839f6d7cbc4afdb295592 Mon Sep 17 00:00:00 2001
From: flu0r1ne <flu0r1ne@flu0r1ne.net>
Date: Sun, 22 Aug 2021 02:09:17 -0500
Subject: Add update script

---
 git-update-agent | 320 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 320 insertions(+)
 create mode 100644 git-update-agent

(limited to 'git-update-agent')

diff --git a/git-update-agent b/git-update-agent
new file mode 100644
index 0000000..0a75161
--- /dev/null
+++ b/git-update-agent
@@ -0,0 +1,320 @@
+#!/bin/sh
+
+# GLOBAL VARIABLES:
+# - AGENT:           Name of the project which is receiving updates (for display purposes)
+# - UPSTREAM_BRANCH: The branch in the upstream repo used for updates (defaults to remote's head if set)
+# - REMOTE:          Name of the remote used for updates
+# - REMOTE_URL:      Name of URL used for synchronization
+
+# USAGE:
+#
+# Initialize a project:
+# git-update-agent --init https://git.mydomain.com
+#
+# Update:
+# git-update-agent
+
+CMD_PROMPT="[#] "
+PROGRAM="${0##*/}"
+
+die () {
+  if [[ $# -eq 0 ]]; then
+    echo -n "$PROGRAM: " 1>&2
+    cat <&0 1>&2
+  elif [[ $# -eq 1 ]]; then
+    echo "$PROGRAM: $1" 1>&2
+  fi
+
+  exit 1
+}
+
+depends() {
+  if ! type "$1" >/dev/null; then
+    die "\"$1\" must be installed and in your \$PATH"
+  fi
+}
+
+cmd() {
+  echo "$CMD_PROMPT $*"
+  "$@"
+}
+
+stash() {
+  if ! git                                \
+    -c "user.email=git-updater@localhost" \
+    -c "user.name=git-updater"            \
+    stash save --include-untracked &>/dev/null
+  then
+
+  die <<_EOF
+Could not stash in $(pwd)
+Please stash/commit manually if you need to keep your changes. If you would like to destroy all changes, run:
+cd $(pwd)
+git reset --hard origin/main
+_EOF
+
+  fi
+}
+
+current_version() {
+  git rev-parse -q --verify HEAD
+}
+      
+die_no_upstream_found() {
+  die <<_EOF
+origin/HEAD is used as the reference for updates
+origin/HEAD is not set and UPSTREAM_BRANCH override not provided
+
+You can set the upstream branch with:
+git remote set-head <name> <branch>
+_EOF
+}
+
+upstream_branch() {
+  local upstream_branch
+  local remote
+
+  remote="$1"
+
+
+  if [[ -z "$UPSTREAM_BRANCH" ]]; then
+    upstream_branch="$(git symbolic-ref "refs/remotes/$remote/HEAD" 2>/dev/null)"
+    upstream_branch="${upstream_branch#refs/remotes/$remote/}"
+  else
+    upstream_branch="$UPSTREAM_BRANCH"
+  fi
+
+  echo "$upstream_branch"
+}
+
+local_branch() {
+  local branch
+
+  branch="$(git symbolic-ref HEAD)"
+  branch="${branch#refs/heads/}"
+
+  echo "$branch"
+}
+
+merge() {
+  local STASHED
+  
+  local remote
+  local remote_branch 
+  local local_branch
+
+  remote="$1"
+  remote_branch="$2"
+  local_branch="$3"
+  
+  local remote_ref
+  remote_ref="$remote/$remote_branch"
+
+
+  if [[ -n "$(git status --untracked-files=all --porcelain 2>/dev/null)" ]]; then
+    # Abort rebase or merge if initiated
+    git merge --abort  &>/dev/null
+    git rebase --abort &>/dev/null
+
+    stash
+    STASHED="1"
+  fi
+
+  # Attempt fetch to REMOTE/UPSTREAM_BRANCH
+  if ! git fetch --tags --force "$remote" \
+    "refs/heads/$remote_branch:refs/remotes/$remote_ref"
+  then
+    die "Cannot fetch from $remote_ref from $local_branch"
+  fi
+
+  # Try fast-forward merge
+  git merge --no-edit --ff "$remote_ref" \
+      --strategy=recursive \
+      --strategy-option=ours \
+      --strategy-option=ignore-all-space \
+      >/dev/null
+
+  if [[ -n "$STASHED" && -z "$NO_STASH_POP" ]]; then
+    git stash pop &>/dev/null
+  fi
+}
+
+remote() {
+  local remote
+
+  if [[ -z "$REMOTE" ]]; then
+    remote="origin"
+  else
+    remote="$REMOTE"
+  fi
+
+  echo "$remote"
+}
+
+cd_or_die() {
+  cd "$1" || die "Cannot enter directory $1. Exiting."
+}
+
+die_no_git_dir() {
+  die <<_EOF
+Cannot find a .git directory in $(pwd). Try initializing repo with:
+$PROGRAM --init-with https://git.example.com
+
+To automatically create a git repo, consider setting "REMOTE_URL"
+_EOF
+}
+
+init_if_empty() {
+  if [[ ! -d ".git" ]]; then
+
+    if [[ -z "$REMOTE_URL" ]]; then 
+      die_no_git_dir
+    else
+      init_repo "$REMOTE_URL"
+    fi
+
+  fi
+}
+
+update() {
+  local dir
+  local previous_version
+  local next_version
+
+  dir="$1"
+  cd_or_die "$dir"
+
+  previous_version="$(current_version)"
+
+  if [[ -z "$AGENT" ]]; then
+    AGENT="$(basename "$(pwd)")"
+  fi
+
+  depends git
+
+  init_if_empty
+
+  local remote
+  local remote_branch
+  local local_branch
+
+  remote="$(remote)"
+  
+  remote_branch="$(upstream_branch "$remote")"
+
+  if [[ -z "$remote_branch" ]]; then
+    die_no_upstream_found
+  fi
+
+  local_branch="$(local_branch)"
+
+  merge "$remote" "$remote_branch" "$local_branch"
+
+  next_version="$(current_version)"
+
+  if [[ "$previous_version" == "" ]]; then
+    echo "Initialized $AGENT with \"$previous_version\""
+  elif [[ "$previous_version" != "$next_version" ]]; then
+    echo "Updated $AGENT from version \"$previous_version\" to \"$next_version\""
+  else
+    echo "$AGENT is already up to date."
+  fi
+}
+
+print_usage() {
+cat <<_EOF
+Usage: ${PROGRAM} [OPTIONS]...
+  -h, --help     output this help info
+  -d, --dir      update in directory
+  --init         initialize a project with the given URL
+_EOF
+}
+
+init_repo() {
+  local remote
+  local remote_url
+  local upstream_branch
+  local remote_ref
+
+  remote_url="$1"
+  remote="$(remote)"
+
+  DEFAULT_BRANCH="main"
+
+  trap '{ rm -rf .git; exit 1; }' EXIT
+
+  set -e
+  git init &>/dev/null
+  git branch -M "$DEFAULT_BRANCH"
+  git config remote.origin.url "$remote_url"
+  git config remote.origin.fetch "+refs/heads/*:refs/remotes/$remote/*"
+  git fetch --force --tags "$remote" &>/dev/null
+  git remote set-head "$remote" --auto >/dev/null
+  
+  upstream_branch="$(upstream_branch "$remote")"
+
+  if [[ -z "$upstream_branch" ]]; then
+    die_no_upstream_found
+  fi
+
+  remote_ref="$remote/$upstream_branch"
+
+  git merge --ff --no-edit "$remote_ref"
+
+  git branch --set-upstream-to="$remote_ref" "$DEFAULT_BRANCH"
+
+  git reset --hard "$remote_ref" >/dev/null
+
+  trap - EXIT
+
+  set +e
+}
+
+git_update_agent() {
+  local dir
+  local option
+  local remote_url
+
+  while [[ $# -gt 0 ]]; do
+    case "$1" in
+      -h|-\?|--help|--usage) print_usage; exit 0 ;;
+      --dir)
+        
+        shift
+
+        if [[ $# -eq 0 ]]; then
+          die "--dir requires an option"
+        fi
+
+        dir="$1"
+
+        shift
+      ;;
+      --init-with)
+
+        shift
+
+        if [[ $# -eq 0 ]]; then
+          die "--init requires an option"
+        fi
+
+        remote_url="$1"
+
+        shift
+      ;;
+      *) die "$(print_usage)" ;;
+    esac
+  done
+
+  if [[ -z "$dir" ]]; then
+    dir="." 
+  fi
+
+  if [[ -z "$remote_url" ]]; then
+    update "$dir"
+  else
+    init_repo "$remote_url"
+  fi
+}
+
+git_update_agent "$@"
-- 
cgit v1.2.3