blob: d1f3006c0e9eee6005951077eda9ca607e89f659 [file] [log] [blame]
#!/bin/bash
# Get number of CPUs for parallel processing
NR_CPUS=$(nproc)
# Debug mode flag
DEBUG=0
if [[ "${@-}" == *"--debug"* ]]; then
DEBUG=1
fi
# Debug logging function
debug_log() {
if [[ "${DEBUG-0}" == "1" ]]; then
echo "[DEBUG] $*" >&2
fi
}
# Function to extract the first SHA1 from changelog body
extract_sha1() {
local content="$1"
# Look for 40-character hex string in the entire content
local sha1=$(echo "$content" | grep -o '[0-9a-f]\{40\}' | head -n 1 || echo "NO_SHA")
debug_log "Extracted SHA1: $sha1"
echo "$sha1"
}
# Function to check if a file was moved rather than deleted
is_moved() {
local file="$1"
local commit="$2"
local ver="$3"
debug_log "Checking if $file was moved in commit $commit for version $ver"
# Check if the file appears in the same commit with R status (rename)
# Look in both queue-${ver} and releases/${ver}.*
local result=$(git log -1 --format=%H --full-history --diff-filter=R -- "$file" "releases/${ver}.*" | grep -q "$commit"; echo $?)
if [ $result -eq 0 ]; then
debug_log "File was moved"
else
debug_log "File was not moved"
fi
return $result
}
# Function to check if upstream id exists in releases directory
is_readded() {
local ver="$1"
local upstream_id="$2"
debug_log "Checking if $upstream_id was readded for version $ver"
# Recursive grep on releases/${ver}.* pattern
local result=$(grep -r -q "$upstream_id" releases/${ver}.* 2>/dev/null; echo $?)
if [ $result -eq 0 ]; then
debug_log "Found readded in releases"
else
debug_log "Not found in releases"
fi
return $result
}
# Function to check if entry already exists in dropped_commits
is_known_drop() {
local ver="$1"
local upstream_id="$2"
local dropped_commits="$3"
local result=$(grep -q "^$ver $upstream_id\$" "$dropped_commits"; echo $?)
if [ $result -eq 0 ]; then
debug_log "Already known drop: $ver $upstream_id"
else
debug_log "New drop found: $ver $upstream_id"
fi
return $result
}
# Function to get the commit range to process
get_commit_range() {
local dropped_commits="$1"
debug_log "Getting commit range from $dropped_commits"
if [ ! -f "$dropped_commits" ] || [ ! -s "$dropped_commits" ]; then
debug_log "No dropped_commits file or empty file"
echo "Processing full history" >&2
echo "" # Return empty string to indicate full history
return 0
fi
# Get the last line and trim whitespace
local last_line=$(tail -n 1 "$dropped_commits" | tr -d '[:space:]')
debug_log "Last line from dropped_commits: $last_line"
# Check if last_line is empty
if [ -z "$last_line" ]; then
debug_log "Last line is empty"
echo "Last line is empty, processing full history" >&2
echo ""
return 0
fi
# Check if the last line is a valid commit
if echo "$last_line" | grep -qE '^[0-9a-f]{40}$' && git rev-parse --verify "$last_line^{commit}" >/dev/null 2>&1; then
debug_log "Valid commit found: $last_line"
echo "Processing commits from $last_line..HEAD" >&2
echo "$last_line..HEAD"
return 0
fi
debug_log "Invalid commit in last line"
echo "Last line is not a valid commit, processing full history" >&2
echo ""
}
# Function to process a single commit
process_commit() {
local ver="$1"
local commit="$2"
local tmpfile="$3"
local dropped_commits="$4"
debug_log "Processing commit $commit for version $ver"
# Skip empty commits
[ -z "$commit" ] && {
debug_log "Skipping empty commit"
return
}
# Get the files deleted in this commit
debug_log "Getting deleted files for commit $commit"
git show --diff-filter=D --name-only --pretty="" "$commit" -- "queue-${ver}" | \
while IFS= read -r file; do
# Skip empty lines
[ -z "$file" ] && continue
debug_log "Processing deleted file: $file"
# Get commit content and SHA1
debug_log "Getting content for $file from parent commit"
local content=$(git show --format="%B" "$commit^:$file" 2>/dev/null)
if [ $? -ne 0 ]; then
debug_log "Failed to get content for $file"
continue
fi
local sha1=$(extract_sha1 "$content")
if [ "$sha1" = "NO_SHA" ]; then
debug_log "No SHA1 found in content"
continue
fi
# Skip if already known
if [ -f "$dropped_commits" ] && is_known_drop "$ver" "$sha1" "$dropped_commits"; then
debug_log "Skipping known drop: $ver $sha1"
continue
fi
# Check if file was moved rather than deleted
if ! is_moved "$file" "$commit" "$ver"; then
# Check if file exists in the latest commit
if ! git show HEAD:"$file" &>/dev/null; then
debug_log "File not in HEAD"
# Only output if the patch wasn't readded
if ! is_readded "$ver" "$sha1"; then
debug_log "Adding new drop: $ver $sha1"
# Use flock for thread-safe file writing
(
flock -x 200
echo "$ver $sha1" >&3
) 200>"$tmpfile.lock"
fi
else
debug_log "File exists in HEAD"
fi
else
debug_log "File was moved, skipping"
fi
done
}
export -f process_commit extract_sha1 is_moved is_readded is_known_drop debug_log
# Main processing
process_repo() {
local tmpfile=$(mktemp)
local dropped_commits="scripts/dropped_commits"
debug_log "Starting process_repo with tmpfile: $tmpfile"
# Create scripts directory if it doesn't exist
mkdir -p scripts
touch "$dropped_commits"
# Get commit range to process
local commit_range=$(get_commit_range "$dropped_commits")
debug_log "Got commit range: $commit_range"
# Process versions and collect new entries
exec 3>"$tmpfile"
while IFS= read -r ver; do
# Skip empty lines and comments
[[ -z "$ver" || "$ver" =~ ^# ]] && continue
debug_log "Processing version $ver"
# Get all commits that deleted files
local git_log_cmd="git log --diff-filter=D --format=%H"
if [ -n "$commit_range" ]; then
git_log_cmd="$git_log_cmd $commit_range"
fi
git_log_cmd="$git_log_cmd -- queue-${ver}"
debug_log "Git log command: $git_log_cmd"
# Execute git log and ensure non-empty output
local commits=$(eval "$git_log_cmd")
if [ $? -ne 0 ]; then
debug_log "git log failed for version $ver"
continue
fi
if [ -z "$commits" ]; then
debug_log "No commits found for version $ver"
continue
else
debug_log "Found commits for version $ver: $commits"
fi
# Process commits (parallel only in non-debug mode)
if [[ "${DEBUG-0}" == "1" ]]; then
echo "$commits" | while read -r commit; do
process_commit "$ver" "$commit" "$tmpfile" "$dropped_commits"
done
else
echo "$commits" | \
parallel --halt now,fail=1 -j "$NR_CPUS" --line-buffer \
process_commit "$ver" {} "$tmpfile" "$dropped_commits"
fi
done < "active_kernel_versions"
exec 3>&-
debug_log "Processing complete, creating sorted file"
# Create new sorted file with unique entries
{
if [ -s "$dropped_commits" ]; then
debug_log "Keeping existing entries from dropped_commits"
head -n -1 "$dropped_commits"
fi
debug_log "Adding new entries from tmpfile"
cat "$tmpfile"
} | sort -rV -k1,1 -k2,2 | uniq > "${tmpfile}.sorted"
# Add current HEAD commit as the last line
git rev-parse HEAD >> "${tmpfile}.sorted"
# Only update if there are changes
if ! cmp -s "${tmpfile}.sorted" "$dropped_commits"; then
debug_log "Changes detected, updating dropped_commits"
mv "${tmpfile}.sorted" "$dropped_commits"
echo "Updated scripts/dropped_commits with new entries" >&2
else
debug_log "No changes detected"
echo "No new entries to add to scripts/dropped_commits" >&2
rm -f "${tmpfile}.sorted"
fi
# Cleanup
rm -f "$tmpfile" "$tmpfile.lock"
}
# Ensure we're in a git repository
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
echo "Error: Not in a git repository" >&2
exit 1
fi
# Ensure active_kernel_versions file exists
if [ ! -f "active_kernel_versions" ]; then
echo "Error: active_kernel_versions file not found" >&2
exit 1
fi
# Ensure GNU parallel is available
if ! command -v parallel >/dev/null 2>&1; then
echo "Error: GNU parallel is not installed" >&2
exit 1
fi
# Export debug flag for parallel
export DEBUG="${DEBUG-0}"
# Run the main process
process_repo