1
0
Files
nix-shared/pkgs/tb-scripts/jq_reformat.sh

136 lines
3.2 KiB
Bash
Raw Normal View History

Add custom script packages with Nix dependency management This commit introduces two new custom script packages: tb-scripts for all systems and tb-dev-scripts for development machines. These packages provide a maintainable way to distribute utility scripts across the infrastructure with proper dependency management. Created pkgs/ directory with two script collections: 1. **tb-scripts** - General utilities available on all systems: - ,jq_reformat: Reformat JSON files in-place with atomic file operations - ,rename_lower: Convert filenames to lowercase with validation 2. **tb-dev-scripts** - Development-specific tools: - ,cmake_update_fetchcontent: Update CMake FetchContent dependencies All scripts have been significantly enhanced from their original versions: - Proper quoting to handle filenames with spaces - Secure temporary file creation using mktemp - Atomic file replacement to prevent data loss - Input validation and comprehensive error handling - Usage help with -h/--help flag - Extensive inline comments explaining each section - Cleanup traps on error - Complete rewrite in Python for consistency - Validates files exist before attempting rename - Checks if target lowercase filename already exists - Skips files already lowercase (no-op) - Descriptive error messages for each failure case - Usage documentation with examples - Proper exit codes - Interactive CMake FetchContent dependency updater - Recursively finds all CMakeLists.txt files via add_subdirectory() - Queries GitHub API for latest releases/tags - Compares semantic versions and commit hashes - Shows available updates in formatted table - Prompts for confirmation before applying updates - Atomic file updates with validation Scripts are packaged using writeShellApplication with proper dependency injection via runtimeInputs: - tb-scripts requires: jq, python3 - tb-dev-scripts requires: python3, git Dependencies are automatically available in PATH when scripts run, eliminating manual dependency checks. Created system module files to import the script packages: - system/default/scripts.nix: Adds tb-scripts to nixosModules.default - system/develop/scripts.nix: Adds tb-dev-scripts to nixosModules.develop Updated flake.nix to import these modules in the appropriate contexts. - Scripts have proper Nix-managed dependencies - No manual installation or PATH configuration needed - Easy to extend with additional scripts - Scripts are validated with shellcheck during build - Clear separation between all-systems and dev-only utilities - Comprehensive error handling and user documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-19 05:15:37 -08:00
#!/usr/bin/env bash
#
# jq_reformat - Reformat JSON files in-place using jq
#
# Usage: jq_reformat FILE [FILE...]
#
# This script reformats JSON files in-place by running them through jq.
# It preserves the original files by using atomic temporary file replacement,
# ensuring data safety even if the process is interrupted.
#
# Examples:
# jq_reformat config.json
# jq_reformat *.json
# jq_reformat data/*.json settings.json
#
set -euo pipefail
#
# Show usage information
#
usage() {
cat <<EOF
Usage: ,jq_reformat FILE [FILE...]
Reformat JSON files in-place using jq.
This script reformats JSON files by running them through jq's parser,
which produces consistently formatted, valid JSON. Files are updated
atomically using temporary files to prevent data loss.
Arguments:
FILE One or more JSON files to reformat
Options:
-h, --help Show this help message
Examples:
,jq_reformat config.json
,jq_reformat *.json
,jq_reformat data/*.json settings.json
Exit codes:
0 Success - all files reformatted
1 Error - invalid arguments, missing files, or jq errors
EOF
}
#
# Reformat a single JSON file in-place
#
# Arguments:
# $1 - Path to the JSON file to reformat
#
# Returns:
# 0 on success, 1 on error
#
reformat_file() {
local file="$1"
local temp_file
# Validate that the file exists and is readable
if [[ ! -f "$file" ]]; then
echo "Error: File not found: $file" >&2
return 1
fi
if [[ ! -r "$file" ]]; then
echo "Error: File not readable: $file" >&2
return 1
fi
# Create a secure temporary file in the same directory as the target
# This ensures we're on the same filesystem for atomic mv operation
temp_file=$(mktemp "${file}.XXXXXX") || {
echo "Error: Failed to create temporary file for: $file" >&2
return 1
}
# Set up cleanup trap to remove temp file on error
# shellcheck disable=SC2064
trap "rm -f '$temp_file'" EXIT ERR
# Run jq to reformat the JSON
# - Read from the original file
# - Write to temp file
# - If successful, atomically replace the original
if jq . <"$file" >"$temp_file" 2>/dev/null; then
# Preserve original file permissions
chmod --reference="$file" "$temp_file" 2>/dev/null || true
# Atomically replace the original file
mv "$temp_file" "$file"
# Clear the trap since we succeeded
trap - EXIT ERR
return 0
else
# jq failed - the file is likely not valid JSON
echo "Error: Failed to parse JSON in: $file" >&2
rm -f "$temp_file"
trap - EXIT ERR
return 1
fi
}
#
# Main script logic
#
main() {
# Handle help flag
if [[ $# -eq 0 ]] || [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then
usage
[[ $# -eq 0 ]] && return 1
return 0
fi
local exit_code=0
local file
# Process each file argument
# Using "$@" properly handles filenames with spaces and special characters
for file in "$@"; do
if ! reformat_file "$file"; then
exit_code=1
# Continue processing other files even if one fails
fi
done
return "$exit_code"
}
# Run main function with all arguments
main "$@"