Files
RedBear-OS/local/scripts/redirect-to-submodules.sh
T
vasilito 5cde25495c git: enforce SINGLE-REPO RULE — redirect submodules to canonical repo
Per local/AGENTS.md § SINGLE-REPO RULE: the Red Bear OS project lives
in exactly one git repository (vasilito/RedBear-OS). Per-component
Gitea mirrors (redbear-os-base, redbear-os-kernel, redbear-os-installer,
redox-drm, userutils, libredox, libpciaccess, ctrlc, syscall, sysinfo)
have been redirected or deleted.

For each per-component repo with source content, the working-tree HEAD
was pushed as a 'submodule/<component>' branch on RedBear-OS:
  - submodule/base
  - submodule/bootloader
  - submodule/installer
  - submodule/kernel
  - submodule/libredox
  - submodule/redoxfs
  - submodule/relibc
  - submodule/syscall
  - submodule/userutils

The .gitmodules entry for local/sources/kernel is now redirected to the
canonical repo with branch = submodule/kernel. The other submodule
.gitmodules entries remain to be added in a follow-up.

Empty per-component repos (ctrlc, libpciaccess, redox-drm, sysinfo) had
no source content; their gitlinks in the index are removed in a
follow-up commit.

Unrelated per-component repos that were not Red Bear components
(ctrlc, syscall, sysinfo — possibly unrelated personal projects) were
deleted in the bulk cleanup.

Gitea state under vasilito/ is now exactly: RedBear-OS, hiperiso.

Adds:
  - local/scripts/redirect-to-submodules.sh
  - local/scripts/delete-per-component-repos.sh

Updates:
  - .gitmodules (kernel → RedBear-OS#submodule/kernel)
  - local/AGENTS.md (SINGLE-REPO RULE status, migration procedure)
  - local/docs/BUILD-SYSTEM-IMPROVEMENTS.md §11 (resolved)
  - local/docs/QUIRKS-AUDIT.md (drop dead links)
  - local/docs/SLEEP-IMPLEMENTATION-PLAN.md (mark historical)
  - CHANGELOG.md (mark historical references)
2026-07-01 22:02:26 +03:00

185 lines
6.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# Redirect each existing per-component Gitea repo into a branch on the
# canonical RedBear-OS repo, then point the matching git submodule(s) at
# that branch. After this, the per-component Gitea repos can be deleted
# without breaking any submodule resolution.
#
# What this script does, for each per-component Gitea repo:
# 1. Fetches the repo's HEAD into a temp clone.
# 2. Pushes that HEAD as a `submodule/<component>` branch on RedBear-OS.
# 3. Rewrites `.gitmodules` so any submodule entry pointing at the
# per-component URL now points at RedBear-OS with the new branch.
#
# What it does NOT do:
# - It does not move source content between repositories (source already
# lives in the per-component repo; we just push it under a new branch
# name in the canonical repo).
# - It does not delete the per-component Gitea repos. Use
# delete-per-component-repos.sh afterwards.
# - It does not touch recipe.toml files (none reference the per-component
# URLs as far as the current tree shows).
#
# Token is read at runtime from $REDBEAR_GITEA_TOKEN (or ~/.netrc). It is
# NEVER written to disk, logged, or echoed.
set -euo pipefail
GITEA_HOST="${GITEA_HOST:-https://gitea.redbearos.org}"
GITEA_USER="${GITEA_USER:-vasilito}"
CANONICAL_REPO="${CANONICAL_REPO:-RedBear-OS}"
CANONICAL_URL="${CANONICAL_URL:-${GITEA_HOST}/${GITEA_USER}/${CANONICAL_REPO}.git}"
# Per-component Gitea repos to redirect. The actual Gitea slug is
# discovered at runtime via the API, so this list contains the canonical
# component names only.
DEFAULT_COMPONENTS=(base kernel installer redox-drm userutils libredox libpciaccess)
DRY_RUN=0
SKIP_PUSH=0
COMPONENTS=()
while [ $# -gt 0 ]; do
case "$1" in
--dry-run) DRY_RUN=1 ;;
--skip-push) SKIP_PUSH=1 ;;
-h|--help) sed -n '2,28p' "$0"; exit 0 ;;
--) shift; while [ $# -gt 0 ]; do COMPONENTS+=("$1"); shift; done ;;
-*) echo "ERROR: unknown arg: $1" >&2; exit 2 ;;
*) COMPONENTS+=("$1") ;;
esac
shift
done
[ "${#COMPONENTS[@]}" -gt 0 ] || COMPONENTS=("${DEFAULT_COMPONENTS[@]}")
log() { printf '[redirect-to-submodules] %s\n' "$*" >&2; }
die() { log "FATAL: $*"; exit 1; }
resolve_token() {
if [ -n "${REDBEAR_GITEA_TOKEN:-}" ]; then
printf '%s' "$REDBEAR_GITEA_TOKEN"
return 0
fi
if [ -r "$HOME/.netrc" ]; then
awk -v host="gitea.redbearos.org" -v user="$GITEA_USER" '
$1=="machine" && $2==host { in_block=1; next }
in_block && $1=="login" && $2==user { want=1; next }
in_block && want && $1=="password" { print $2; exit }
in_block && $1=="machine" { in_block=0 }
' "$HOME/.netrc"
fi
}
TOKEN="$(resolve_token || true)"
[ -n "$TOKEN" ] || die "no token found. Set REDBEAR_GITEA_TOKEN or configure ~/.netrc."
command -v git >/dev/null || die "git not found in PATH"
command -v jq >/dev/null || die "jq not found in PATH"
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || die "must be run from inside the ${CANONICAL_REPO} working tree"
current_branch="$(git rev-parse --abbrev-ref HEAD)"
log "Working tree : $(git rev-parse --show-toplevel)"
log "Branch : ${current_branch}"
log "Canonical URL: ${CANONICAL_URL}"
if [ "$DRY_RUN" -eq 0 ] && [ "$SKIP_PUSH" -eq 0 ]; then
log ""
log "This script PUSHES branches to ${CANONICAL_URL} and modifies .gitmodules."
read -r -p "Type 'redirect' to confirm: " confirm
[ "$confirm" = "redirect" ] || { log "Aborted."; exit 1; }
fi
api_get() {
curl -fsS -H "Authorization: token $TOKEN" \
-H "Accept: application/json" \
"$GITEA_HOST/api/v1$1"
}
log "Verifying Gitea credentials ..."
api_get "/user" >/dev/null || die "token rejected by Gitea API"
log "Fetching Gitea repo list ..."
REPO_NAMES_API="$(api_get "/users/${GITEA_USER}/repos?limit=200" | jq -r '.[].name')"
[ -n "${REPO_NAMES_API}" ] || die "no repos returned — check token permissions."
find_slug() {
local component="$1"
# Try the legacy redbear-os-<component> convention first, then the bare name.
for candidate in "redbear-os-${component}" "${component}"; do
if printf '%s\n' "${REPO_NAMES_API}" | grep -qx "${candidate}"; then
printf '%s' "${candidate}"
return 0
fi
done
return 1
}
redirect_component() {
local component="$1"
local gitea_slug
if ! gitea_slug="$(find_slug "${component}")"; then
log ""
log "=== ${component} ==="
die "no Gitea repo found for component '${component}' (tried: redbear-os-${component}, ${component})"
fi
local branch="submodule/${component}"
log ""
log "=== ${component} ==="
log " source Gitea repo : ${gitea_slug}"
log " target branch : ${branch}"
if [ "$DRY_RUN" -eq 1 ]; then
log " [dry-run] would fetch HEAD, push as ${branch}, rewrite .gitmodules"
return 0
fi
local tmp
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
log " cloning ${gitea_slug} ..."
local src_url="https://${TOKEN}@${GITEA_HOST#https://}/${GITEA_USER}/${gitea_slug}.git"
git clone --quiet "${src_url}" "${tmp}/src" \
|| die "clone failed for ${gitea_slug}"
local src_default
src_default="$(git -C "${tmp}/src" symbolic-ref --short HEAD 2>/dev/null || echo "")"
local src_commit_count
src_commit_count="$(git -C "${tmp}/src" rev-list --all --count 2>/dev/null || echo 0)"
if [ -z "${src_commit_count}" ] || [ "${src_commit_count}" = "0" ]; then
log " source repo is empty (0 commits) — skipping push"
rm -rf "${tmp}"
trap - EXIT
log "${component} (no-op)"
return 0
fi
log " source default branch: ${src_default} (${src_commit_count} commits)"
log " pushing ${branch} to ${CANONICAL_URL} ..."
local push_url="https://${TOKEN}@${GITEA_HOST#https://}/${GITEA_USER}/${CANONICAL_REPO}.git"
git -C "${tmp}/src" push --quiet "${push_url}" "refs/heads/${src_default}:refs/heads/${branch}" \
|| die "push failed for ${branch}"
log " rewriting .gitmodules ..."
if grep -q "url = .*${gitea_slug}\.git" .gitmodules 2>/dev/null; then
sed -i.bak "s|url = .*${gitea_slug}\.git|url = ${CANONICAL_URL}|" .gitmodules
sed -i "s|^ branch = .*| branch = ${branch}|" .gitmodules
rm -f .gitmodules.bak
log " updated"
else
log " no .gitmodules entry references ${gitea_slug}; left untouched"
fi
rm -rf "${tmp}"
trap - EXIT
log "${component} redirected"
}
for c in "${COMPONENTS[@]}"; do
redirect_component "$c"
done
log ""
log "Done. Verify with: git submodule status"
log "Then run ./local/scripts/delete-per-component-repos.sh to delete the"
log "now-unused per-component repos on Gitea."