From 528a6d9303c00e91de44c053d58e7aae55ba1d83 Mon Sep 17 00:00:00 2001 From: Slipstream Date: Thu, 5 Jun 2025 16:25:31 -0600 Subject: [PATCH] Refactor: Implement blame percentage calculation scripts for PowerShell and Bash with error handling --- blamepercent.ps1 | 60 +++++++++++++++++++++++++++++++ blamepercent.sh | 94 ++++++++++++++++++++++++++++++++++++++++++++++++ fuckass.ps1 | 10 ------ 3 files changed, 154 insertions(+), 10 deletions(-) create mode 100644 blamepercent.ps1 create mode 100644 blamepercent.sh delete mode 100644 fuckass.ps1 diff --git a/blamepercent.ps1 b/blamepercent.ps1 new file mode 100644 index 0000000..c53b3cd --- /dev/null +++ b/blamepercent.ps1 @@ -0,0 +1,60 @@ +param ( + [string]$FilePath +) + +# --- Add this block for error handling --- +if ([string]::IsNullOrEmpty($FilePath)) { + Write-Error "Error: No file path provided." + Write-Host "Usage: .\blamepercent.ps1 -FilePath " + Write-Host "Example: .\blamepercent.ps1 -FilePath '.\your_script.ps1'" + exit 1 +} +# --- End of added block --- + +if (-not (Test-Path $FilePath)) { + Write-Error "File '$FilePath' does not exist." + exit 1 +} + +# Set console output to UTF-8 +[Console]::OutputEncoding = [Text.UTF8Encoding]::new() + +# Run git blame on the file, get author names per line +$blameOutput = git blame --line-porcelain $FilePath | Where-Object { $_ -like 'author *' } | ForEach-Object { ($_ -replace 'author ', '').Trim() } + +if (-not $blameOutput) { + Write-Error "No git blame info found. Make sure this file is tracked by git." + exit 1 +} + +# Function to sanitize author names, removing problematic characters +function Clean-AuthorName { + param($name) + # Remove control characters and non-printable characters + $clean = -join ($name.ToCharArray() | Where-Object { + $c = [int][char]$_ + ($c -ge 32 -and $c -le 126) -or ($c -ge 160) # keep printable ASCII and extended UTF chars + }) + return $clean +} + +# Count lines per author +$authorCounts = @{} +$totalLines = 0 + +foreach ($author in $blameOutput) { + $cleanAuthor = Clean-AuthorName $author + if ($authorCounts.ContainsKey($cleanAuthor)) { + $authorCounts[$cleanAuthor] += 1 + } else { + $authorCounts[$cleanAuthor] = 1 + } + $totalLines++ +} + +# Calculate and display percentages +Write-Host "Code contribution percentages for file: $FilePath" +foreach ($author in $authorCounts.Keys) { + $percentage = [math]::Round(($authorCounts[$author] / $totalLines) * 100, 2) + Write-Host "$author : $percentage %" +} \ No newline at end of file diff --git a/blamepercent.sh b/blamepercent.sh new file mode 100644 index 0000000..f1e5559 --- /dev/null +++ b/blamepercent.sh @@ -0,0 +1,94 @@ +#!/bin/bash + +# --- Input Parameter --- +# Check if file path is provided BEFORE enabling set -u +# This ensures a user-friendly message for missing arguments. +if [ -z "$1" ]; then + echo "Usage: $0 " + exit 1 +fi + +FILE_PATH="$1" + +# --- Error Handling --- +# Exit immediately if a command exits with a non-zero status. +set -e +# Treat unset variables as an error. +# Now that $1 is safely assigned (or the script exited), set -u is safe here. +set -u + +# Check if the file exists +if [ ! -f "$FILE_PATH" ]; then + echo "Error: File '$FILE_PATH' does not exist." + exit 1 +fi + +# Check if git is installed and available +if ! command -v git &> /dev/null; then + echo "Error: 'git' command not found. Please install Git." + exit 1 +fi + +# --- Main Logic --- + +# Run git blame on the file, extract author names +# We use --line-porcelain for detailed output, then grep for 'author ' lines, +# and finally use sed to extract just the author name. +# Sort and uniq -c will give us counts for each author. +blame_output=$(git blame --line-porcelain "$FILE_PATH" | \ + grep '^author ' | \ + sed 's/^author //g') + +if [ -z "$blame_output" ]; then + echo "Error: No git blame info found for '$FILE_PATH'. Make sure this file is tracked by git." + exit 1 +fi + +# Initialize associative array for author counts (Bash 4.0+ required) +declare -A author_counts + +total_lines=0 + +# Clean-AuthorName equivalent: remove control characters and non-printable characters. +# This sed expression keeps printable ASCII (0x20-0x7E) and multi-byte UTF-8 characters. +# It removes characters like carriage returns, newlines, and other control codes. +clean_author_name() { + local name="$1" + # Remove characters not in printable ASCII range or common extended characters. + # This might need refinement depending on the exact non-printable characters encountered. + # For simplicity, we'll focus on removing common control characters. + echo "$name" | tr -d '\0-\031\177' # Remove ASCII control characters and DEL +} + +# Count lines per author +while IFS= read -r author; do + # Call the cleaning function + cleaned_author=$(clean_author_name "$author") + + # DEBUGGING OUTPUT + echo "[DEBUG] Author='$author' Cleaned='$cleaned_author'" >&2 + + # Increment count for the cleaned author + if [[ -n "${author_counts[$cleaned_author]:-}" ]]; then + author_counts["$cleaned_author"]=$((author_counts["$cleaned_author"] + 1)) + else + author_counts["$cleaned_author"]=1 + fi + total_lines=$((total_lines + 1)) +done <<< "$blame_output" + +# Calculate and display percentages +echo "Code contribution percentages for file: $FILE_PATH" + +if [ "$total_lines" -eq 0 ]; then + echo "No lines found to analyze." + exit 0 +fi + +# Iterate over the keys (authors) in the associative array +for author in "${!author_counts[@]}"; do + count="${author_counts[$author]}" + # Use awk for floating-point arithmetic for percentage calculation + percentage=$(awk "BEGIN {printf \"%.2f\", (($count / $total_lines) * 100)}") + echo "$author : $percentage %" +done diff --git a/fuckass.ps1 b/fuckass.ps1 deleted file mode 100644 index 86ce3c9..0000000 --- a/fuckass.ps1 +++ /dev/null @@ -1,10 +0,0 @@ -git log --author="Slipstream" --pretty=tformat: --numstat | - ForEach-Object { - $parts = $_ -split "`t" - if ($parts.Count -ge 2) { - $insertions += [int]$parts[0] - $deletions += [int]$parts[1] - } - } -"Insertions: $insertions" -"Deletions: $deletions" \ No newline at end of file