diff --git a/scripts/maintenance/init-monorepo-from-proxmox-gitmodules.sh b/scripts/maintenance/init-monorepo-from-proxmox-gitmodules.sh new file mode 100755 index 0000000..e01b735 --- /dev/null +++ b/scripts/maintenance/init-monorepo-from-proxmox-gitmodules.sh @@ -0,0 +1,147 @@ +#!/usr/bin/env bash +# Initialize a single Git monorepo directory with the same tree layout as +# proxmox .gitmodules (clone each remote into path, drop nested .git). +# +# Optional: create empty repo on Gitea under an org and push (needs GITEA_TOKEN). +# +# Usage: +# MONOREPO_ROOT=/path/to/empty/dir ./scripts/maintenance/init-monorepo-from-proxmox-gitmodules.sh +# GITEA_TOKEN=... GITEA_ORG=d-bis ./scripts/maintenance/init-monorepo-from-proxmox-gitmodules.sh --create-remote --push +# +# Env: +# PROXMOX_ROOT — repo with .gitmodules (default: parent of scripts/maintenance/../../) +# MONOREPO_ROOT — target directory (default: $HOME/projects/complete-credential) +# GITEA_URL — default https://gitea.d-bis.org +# GITEA_ORG — default d-bis (this instance has no org slug "DBIS"; create it in Gitea or override) +# GITEA_TOKEN — for API create + HTTPS push +# SHALLOW — if 1, git clone --depth 1 (default 1) + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROXMOX_ROOT="${PROXMOX_ROOT:-$(cd "$SCRIPT_DIR/../.." && pwd)}" +MONOREPO_ROOT="${MONOREPO_ROOT:-$HOME/projects/complete-credential}" +GITEA_URL="${GITEA_URL:-https://gitea.d-bis.org}" +GITEA_ORG="${GITEA_ORG:-d-bis}" +SHALLOW="${SHALLOW:-1}" + +CREATE_REMOTE=0 +DO_PUSH=0 +for arg in "$@"; do + case "$arg" in + --create-remote) CREATE_REMOTE=1 ;; + --push) DO_PUSH=1 ;; + -h|--help) + sed -n '1,25p' "$0" + exit 0 + ;; + esac +done + +GITMODULES="${PROXMOX_ROOT}/.gitmodules" +[[ -f "$GITMODULES" ]] || { echo "ERROR: missing $GITMODULES" >&2; exit 1; } +mkdir -p "$MONOREPO_ROOT" +cd "$MONOREPO_ROOT" + +if [[ -n "$(ls -A "$MONOREPO_ROOT" 2>/dev/null)" ]] && [[ ! -d "$MONOREPO_ROOT/.git" ]]; then + echo "ERROR: $MONOREPO_ROOT is not empty and not a git repo. Use an empty dir or rm -rf contents." >&2 + exit 1 +fi + +manifest="$MONOREPO_ROOT/MONOREPO_SOURCES.txt" +: > "$manifest" +echo "# pathurl — generated from $GITMODULES" >> "$manifest" + +clone_one() { + local rel_path="$1" url="$2" + local dest="$MONOREPO_ROOT/$rel_path" + echo "[clone] $rel_path <= $url" + if [[ -e "$dest" ]]; then + # Parent repo may have created an empty placeholder (e.g. nested submodule path) + if [[ -z "$(find "$dest" -mindepth 1 -maxdepth 1 2>/dev/null | head -1)" ]]; then + rmdir "$dest" 2>/dev/null || rm -rf "$dest" + else + echo " skip: non-empty $dest" + printf '%s\t%s\n' "$rel_path" "$url" >> "$manifest" + return 0 + fi + fi + mkdir -p "$(dirname "$dest")" + local depth_args=() + [[ "$SHALLOW" == "1" ]] && depth_args=(--depth 1) + GIT_TERMINAL_PROMPT=0 git clone "${depth_args[@]}" "$url" "$dest" + rm -rf "$dest/.git" + printf '%s\t%s\n' "$rel_path" "$url" >> "$manifest" +} + +# Deepest paths first so nested submodule dirs (e.g. dbis_core/.../arbitrage) are not masked by parent clone. +pairs_tmp="$(mktemp)" +while read -r key path; do + [[ "$key" =~ ^submodule\.(.+)\.path$ ]] || continue + name="${BASH_REMATCH[1]}" + url="$(git config -f "$GITMODULES" --get "submodule.${name}.url" 2>/dev/null || true)" + [[ -n "$url" && -n "$path" ]] || continue + slashes="${path//[^\/]/}" + printf '%s\t%s\t%s\n' "${#slashes}" "$path" "$url" +done < <(git config -f "$GITMODULES" --get-regexp '^submodule\..*\.path$') | sort -t $'\t' -k1,1nr > "$pairs_tmp" + +while IFS=$'\t' read -r _depth path url; do + clone_one "$path" "$url" || echo "WARN: clone failed for $path ($url)" >&2 +done < "$pairs_tmp" +rm -f "$pairs_tmp" + +if [[ ! -d "$MONOREPO_ROOT/.git" ]]; then + git init -b main "$MONOREPO_ROOT" +fi + +cd "$MONOREPO_ROOT" +cat > README.md </dev/null; then + echo "Nothing new to commit." +else + git commit -m "Initial monorepo: import proxmox submodule remotes as directories" +fi + +REPO_SLUG="$(basename "$MONOREPO_ROOT")" + +if [[ "$CREATE_REMOTE" == "1" ]]; then + [[ -n "${GITEA_TOKEN:-}" ]] || { echo "ERROR: GITEA_TOKEN required for --create-remote" >&2; exit 1; } + api="$GITEA_URL/api/v1/orgs/${GITEA_ORG}/repos" + code="$(curl -sS -o /tmp/gitea-create-repo.json -w '%{http_code}' \ + -H "Authorization: token ${GITEA_TOKEN}" \ + -H 'Content-Type: application/json' \ + -d "{\"name\":\"${REPO_SLUG}\",\"private\":true,\"description\":\"Monorepo from proxmox .gitmodules\"}" \ + "$api")" || true + if [[ "$code" == "201" ]]; then + echo "Created Gitea repo ${GITEA_ORG}/${REPO_SLUG}" + elif [[ "$code" == "409" ]]; then + echo "Repo ${GITEA_ORG}/${REPO_SLUG} already exists (409). Continuing." + else + echo "Gitea API HTTP $code — body:" >&2 + cat /tmp/gitea-create-repo.json >&2 || true + exit 1 + fi +fi + +if [[ "$DO_PUSH" == "1" ]]; then + [[ -n "${GITEA_TOKEN:-}" ]] || { echo "ERROR: GITEA_TOKEN required for --push (HTTPS)" >&2; exit 1; } + remote_url="${GITEA_URL}/${GITEA_ORG}/${REPO_SLUG}.git" + # embed token for one-shot push (user can switch to SSH later) + auth_url="$(echo "$remote_url" | sed "s#https://#https://oauth2:${GITEA_TOKEN}@#")" + git remote remove origin 2>/dev/null || true + git remote add origin "$remote_url" + git push -u "$auth_url" main + echo "Pushed to $remote_url (set credential helper or SSH remote for future pushes)." +fi + +echo "Done. Monorepo at $MONOREPO_ROOT"