{ lib, writeShellApplication, nvfetcher, nix, gnused, coreutils, }: writeShellApplication { name = "nvft"; runtimeInputs = [ nvfetcher nix gnused coreutils ]; text = '' set -euo pipefail # Determine the config directory if [[ -n "''${NVFETCHER_CONFIG_DIR:-}" ]]; then CONFIG_DIR="$NVFETCHER_CONFIG_DIR" elif [[ -f "nvfetcher.toml" ]]; then CONFIG_DIR="$(pwd)" else CONFIG_DIR="''${HOME}/.config/home" fi if [[ ! -f "$CONFIG_DIR/nvfetcher.toml" ]]; then echo "❌ Error: nvfetcher.toml not found in $CONFIG_DIR" exit 1 fi echo "🚀 Updating sources in $CONFIG_DIR" echo "" SOURCES_FILE="$CONFIG_DIR/_sources/generated.nix" # Read Go packages from nvfetcher.toml that need vendorHash updates declare -A GO_PACKAGES # For now, hardcode the known Go packages # TODO: Could parse nvfetcher.toml to auto-detect these GO_PACKAGES["mender-cli"]="modules/home/terminal/hr/mender-cli.nix" # Step 0: Save existing hashes before nvfetcher wipes them echo "💾 Saving existing hashes..." declare -A SAVED_VENDOR_HASHES declare -A SAVED_SOURCE_HASHES if [[ -f "$SOURCES_FILE" ]]; then for source_name in "''${!GO_PACKAGES[@]}"; do # Save vendorHash saved_vendor=$(grep -A20 "^ $source_name = " "$SOURCES_FILE" | grep -oP 'vendorHash = "\K[^"]+' || echo "") if [[ -n "$saved_vendor" ]]; then SAVED_VENDOR_HASHES["$source_name"]="$saved_vendor" echo " Saved $source_name vendorHash: $saved_vendor" fi # Save source sha256 to detect if source changed saved_source=$(grep -A20 "^ $source_name = " "$SOURCES_FILE" | grep -oP 'sha256 = "\K[^"]+' || echo "") if [[ -n "$saved_source" ]]; then SAVED_SOURCE_HASHES["$source_name"]="$saved_source" echo " Saved $source_name sourceHash: $saved_source" fi done fi echo "" # Step 1: Run nvfetcher echo "đŸ“Ļ Step 1: Running nvfetcher..." cd "$CONFIG_DIR" if nvfetcher; then echo "" echo "✅ nvfetcher completed" echo "" else echo "" echo "âš ī¸ nvfetcher had some errors, but continuing with vendor hash updates..." echo "" fi # Step 2: Restore saved vendorHash values echo "đŸ“Ļ Step 2: Restoring saved vendorHash values..." for source_name in "''${!SAVED_VENDOR_HASHES[@]}"; do saved_hash="''${SAVED_VENDOR_HASHES[$source_name]}" echo " Restoring $source_name: $saved_hash" # Add vendorHash back after version line using awk awk -v source="$source_name" -v hash="$saved_hash" ' /^ / && $0 ~ source" = " {in_block=1} in_block && /version = / {print; print " vendorHash = \"" hash "\";"; next} in_block && /^ };/ {in_block=0} {print} ' "$SOURCES_FILE" > "$SOURCES_FILE.tmp" && mv "$SOURCES_FILE.tmp" "$SOURCES_FILE" done echo "" # Step 3: Update Go vendor hashes echo "đŸ“Ļ Step 3: Checking for Go packages that need vendor hash updates..." if [[ ! -f "$SOURCES_FILE" ]]; then echo "❌ Error: Generated sources file not found at $SOURCES_FILE" exit 1 fi if [[ ''${#GO_PACKAGES[@]} -eq 0 ]]; then echo "â„šī¸ No Go packages configured for vendor hash updates" echo "" echo "🎉 All updates complete!" exit 0 fi for source_name in "''${!GO_PACKAGES[@]}"; do package_path="''${GO_PACKAGES[$source_name]}" full_path="$CONFIG_DIR/$package_path" if [[ ! -f "$full_path" ]]; then echo "âš ī¸ Package file not found: $full_path" continue fi echo "" echo "đŸ“Ļ Processing $source_name..." # Check if vendorHash already exists in generated.nix current_vendor=$(grep -A20 "^ $source_name = " "$SOURCES_FILE" | grep -oP 'vendorHash = "\K[^"]+' || echo "") if [[ -n "$current_vendor" ]]; then echo " Current vendorHash: $current_vendor" else echo " No vendorHash found" fi # Check if source hash changed (indicates version/source update) new_source_hash=$(grep -A20 "^ $source_name = " "$SOURCES_FILE" | grep -oP 'sha256 = "\K[^"]+' || echo "") old_source_hash="''${SAVED_SOURCE_HASHES[$source_name]:-}" if [[ -n "$old_source_hash" ]] && [[ "$old_source_hash" == "$new_source_hash" ]]; then echo " Source unchanged (hash: ''${new_source_hash:0:16}...)" echo " ✨ Skipping vendorHash recalculation" continue elif [[ -n "$old_source_hash" ]]; then echo " Source changed!" echo " Old: ''${old_source_hash:0:16}..." echo " New: ''${new_source_hash:0:16}..." echo " → Need to recalculate vendorHash" else echo " New package, calculating vendorHash..." fi # Get version from generated sources new_version=$(nix-instantiate --eval --strict --expr " let pkgs = import {}; sources = pkgs.callPackage $SOURCES_FILE {}; in sources.''${source_name}.version " 2>/dev/null | tr -d '"' || echo "") if [[ -z "$new_version" ]]; then echo "âš ī¸ Could not determine version from generated sources" continue fi echo " Version: $new_version" # Create temporary build directory temp_build=$(mktemp -d) trap 'rm -rf "$temp_build"' EXIT # Copy necessary files cp -r "$CONFIG_DIR/_sources" "$temp_build/" cp "$full_path" "$temp_build/package.nix" # Create build expression cat > "$temp_build/default.nix" << 'NIXEOF' { pkgs ? import {} }: let sources = pkgs.callPackage ./_sources/generated.nix {}; in pkgs.callPackage ./package.nix { inherit sources; } NIXEOF # Temporarily replace hash with fakeHash # Replace both inherited vendorHash and explicit vendorHash assignments sed -i 's|inherit (src) pname version src vendorHash|inherit (src) pname version src;\n vendorHash = lib.fakeHash|g' "$temp_build/package.nix" sed -i 's|vendorHash = "[^"]*";|vendorHash = lib.fakeHash;|g' "$temp_build/package.nix" echo " Calculating correct vendor hash..." # Build and extract the correct hash from error message vendor_hash=$(nix-build "$temp_build/default.nix" 2>&1 | \ grep -oP 'got:\s+\K(sha256-[A-Za-z0-9+/=]+)' | \ head -1 || echo "") if [[ -z "$vendor_hash" ]]; then echo "âš ī¸ Could not calculate vendor hash" echo " The package may have built successfully (current hash is correct)" echo " Or there may be a build error unrelated to vendorHash" continue fi echo " New hash: $vendor_hash" # Update the generated.nix file to include vendorHash # Find the entry and add/update vendorHash after version if grep -q "^ $source_name = " "$SOURCES_FILE"; then # Check if vendorHash already exists if grep -A20 "^ $source_name = " "$SOURCES_FILE" | grep -q "vendorHash"; then # Update existing vendorHash using awk for better multiline handling awk -v source="$source_name" -v hash="$vendor_hash" ' /^ / && $0 ~ source" = " {in_block=1} in_block && /vendorHash = / {sub(/vendorHash = "[^"]*"/, "vendorHash = \"" hash "\"")} in_block && /^ };/ {in_block=0} {print} ' "$SOURCES_FILE" > "$SOURCES_FILE.tmp" && mv "$SOURCES_FILE.tmp" "$SOURCES_FILE" echo "✅ Updated vendorHash in generated.nix" else # Add vendorHash after version line using awk awk -v source="$source_name" -v hash="$vendor_hash" ' /^ / && $0 ~ source" = " {in_block=1} in_block && /version = / {print; print " vendorHash = \"" hash "\";"; next} in_block && /^ };/ {in_block=0} {print} ' "$SOURCES_FILE" > "$SOURCES_FILE.tmp" && mv "$SOURCES_FILE.tmp" "$SOURCES_FILE" echo "✅ Added vendorHash to generated.nix" fi else echo "âš ī¸ Could not find $source_name entry in generated.nix" fi done echo "" echo "🎉 All updates complete!" echo "" echo "Summary:" echo " - Source versions and hashes updated by nvfetcher" echo " - Go vendor hashes recalculated and updated" echo "" echo "Next steps:" echo " - Review changes: git diff" echo " - Test build: home-manager switch or similar" echo " - Commit if everything works" ''; meta = { description = "Update nvfetcher sources and Go vendor hashes"; mainProgram = "nvft"; }; }