|
| 1 | +#!/usr/bin/env bash |
| 2 | +# SPDX-License-Identifier: MPL-2.0 |
| 3 | +# fix-pmpl-drift.sh — Flip legacy PMPL-1.0-or-later SPDX stamps to repo-category target |
| 4 | +# Recipe: recipe-fix-pmpl-drift (confidence: 0.95, auto_fixable: true) |
| 5 | +# |
| 6 | +# Per 2026-06-02 owner directive: |
| 7 | +# sole-owner default → MPL-2.0 |
| 8 | +# son-shared → AGPL-3.0-or-later (confirmed: idaptik, burble, standards, rattlescript, vcl-ut) |
| 9 | +# palimpsest carve-out → KEEP PMPL (palimpsest-license, palimpsest-plasma; consent-aware-http special) |
| 10 | +# 007 → DO NOT TOUCH (ARR) |
| 11 | +# third-party/forks → DO NOT TOUCH |
| 12 | +# |
| 13 | +# Usage: fix-pmpl-drift.sh <repo-path> [--dry-run] [--file <specific-file>] |
| 14 | + |
| 15 | +set -euo pipefail |
| 16 | + |
| 17 | +REPO_PATH="${1:?Usage: fix-pmpl-drift.sh <repo-path> [--dry-run]}" |
| 18 | +DRY_RUN="" |
| 19 | +SPECIFIC_FILE="" |
| 20 | + |
| 21 | +shift |
| 22 | +while [ $# -gt 0 ]; do |
| 23 | + case "$1" in |
| 24 | + --dry-run) DRY_RUN=1 ;; |
| 25 | + --file) SPECIFIC_FILE="$2"; shift ;; |
| 26 | + *) echo "Unknown arg: $1" >&2; exit 1 ;; |
| 27 | + esac |
| 28 | + shift |
| 29 | +done |
| 30 | + |
| 31 | +REPO_NAME=$(basename "$REPO_PATH") |
| 32 | + |
| 33 | +# ─── Carve-out check ─── |
| 34 | +SKIP_REPOS=( |
| 35 | + "007" |
| 36 | + "palimpsest-license" |
| 37 | + "palimpsest-plasma" |
| 38 | + "game-server-admin" |
| 39 | + "airborne-submarine-squadron" |
| 40 | + "paint-type" |
| 41 | +) |
| 42 | +for skip in "${SKIP_REPOS[@]}"; do |
| 43 | + if [ "$REPO_NAME" = "$skip" ]; then |
| 44 | + echo "SKIP: $REPO_NAME is on the exclude_repos list (carve-out or third-party)" |
| 45 | + exit 0 |
| 46 | + fi |
| 47 | +done |
| 48 | + |
| 49 | +# ─── Category classification via LICENSE file ─── |
| 50 | +LICENSE_PATH="$REPO_PATH/LICENSE" |
| 51 | +if [ ! -f "$LICENSE_PATH" ]; then |
| 52 | + echo "WARN: no LICENSE file at $LICENSE_PATH — skipping (cannot classify)" |
| 53 | + exit 0 |
| 54 | +fi |
| 55 | + |
| 56 | +LIC_HEAD=$(head -1 "$LICENSE_PATH" | tr -d '\n') |
| 57 | + |
| 58 | +if echo "$LIC_HEAD" | grep -q "MPL-2.0"; then |
| 59 | + TARGET="MPL-2.0" |
| 60 | + CATEGORY="sole-owner" |
| 61 | +elif echo "$LIC_HEAD" | grep -q "AGPL-3.0"; then |
| 62 | + TARGET="AGPL-3.0-or-later" |
| 63 | + CATEGORY="son-shared" |
| 64 | +elif echo "$LIC_HEAD" | grep -q "PMPL-1.0-or-later"; then |
| 65 | + echo "INFO: $REPO_NAME LICENSE is PMPL-1.0-or-later (carve-out or staging) — skipping" |
| 66 | + exit 0 |
| 67 | +else |
| 68 | + echo "WARN: $REPO_NAME LICENSE is unfamiliar (\"$LIC_HEAD\") — skipping (manual review)" |
| 69 | + exit 0 |
| 70 | +fi |
| 71 | + |
| 72 | +# ─── Sub-path exclusions ─── |
| 73 | +EXCLUDE_PATTERNS=( |
| 74 | + "/.git/" |
| 75 | + "/LICENSES/" |
| 76 | + "/rescript-tea/" |
| 77 | + "/rescript-vite/" |
| 78 | + "/affinescript-vite/" |
| 79 | + "/idaptik-rescript13-staging/" |
| 80 | + "/consent-aware-http/" |
| 81 | +) |
| 82 | +GREP_EXCLUDE="" |
| 83 | +for p in "${EXCLUDE_PATTERNS[@]}"; do |
| 84 | + GREP_EXCLUDE+="${GREP_EXCLUDE:+|}$p" |
| 85 | +done |
| 86 | + |
| 87 | +# ─── Submodule exclusion (skip submodule paths) ─── |
| 88 | +SUB_PATHS="" |
| 89 | +if [ -f "$REPO_PATH/.gitmodules" ]; then |
| 90 | + while IFS= read -r submodule_path; do |
| 91 | + SUB_PATHS+="${SUB_PATHS:+|}${submodule_path}/" |
| 92 | + done < <(grep "path =" "$REPO_PATH/.gitmodules" | awk '{print $3}') |
| 93 | +fi |
| 94 | +[ -n "$SUB_PATHS" ] && GREP_EXCLUDE="$GREP_EXCLUDE|$SUB_PATHS" |
| 95 | + |
| 96 | +# ─── Find drift files ─── |
| 97 | +cd "$REPO_PATH" |
| 98 | +if [ -n "$SPECIFIC_FILE" ]; then |
| 99 | + FILES="$SPECIFIC_FILE" |
| 100 | +else |
| 101 | + FILES=$(grep -rl "SPDX-License-Identifier: PMPL-1.0-or-later" . 2>/dev/null | grep -vE "$GREP_EXCLUDE" || true) |
| 102 | +fi |
| 103 | + |
| 104 | +COUNT=$(echo "$FILES" | grep -c . 2>/dev/null || echo 0) |
| 105 | + |
| 106 | +if [ "$COUNT" -eq 0 ]; then |
| 107 | + echo "OK: $REPO_NAME has no PMPL drift in safe scope" |
| 108 | + exit 0 |
| 109 | +fi |
| 110 | + |
| 111 | +echo "$REPO_NAME ($CATEGORY → $TARGET): $COUNT files with PMPL drift" |
| 112 | + |
| 113 | +if [ -n "$DRY_RUN" ]; then |
| 114 | + echo "$FILES" | head -20 |
| 115 | + [ "$COUNT" -gt 20 ] && echo "... and $((COUNT - 20)) more" |
| 116 | + exit 0 |
| 117 | +fi |
| 118 | + |
| 119 | +# ─── Flip ─── |
| 120 | +echo "$FILES" | xargs sed -i "s|SPDX-License-Identifier: PMPL-1.0-or-later|SPDX-License-Identifier: $TARGET|g" |
| 121 | + |
| 122 | +REMAINING=$(grep -rl "SPDX-License-Identifier: PMPL-1.0-or-later" . 2>/dev/null | grep -vE "$GREP_EXCLUDE" | wc -l) |
| 123 | +echo "Flipped $COUNT files. Remaining PMPL in scope: $REMAINING." |
0 commit comments