Last active
January 8, 2026 09:58
-
-
Save Velrok/de994796aa26f43e62d74e431fe5e8d1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env ruby | |
| # frozen_string_literal: true | |
| require 'tempfile' | |
| require 'fileutils' | |
| # Interactive Homebrew package upgrade manager | |
| # Allows editing the list of outdated packages to selectively update, skip, or delete | |
| # Functional pipeline for Homebrew package upgrades | |
| module BrewUpgrade | |
| # Get outdated packages from brew | |
| def self.fetch_outdated_packages | |
| `brew outdated 2>/dev/null`.lines.map(&:chomp).reject(&:empty?) | |
| end | |
| # Prefix each line with 'update ' | |
| def self.prefix_with_update(lines) | |
| lines.map { |line| "update #{line}" } | |
| end | |
| # Create instructions header for the temp file | |
| def self.create_header | |
| [ | |
| "# Interactive Homebrew Upgrade", | |
| "# Default: 'update' (or 'up', 'u') - packages will be upgraded", | |
| "# Change to 'skip' (or 's') to skip packages", | |
| "# Change to 'uninstall' (or 'remove', 'rm', 'del') to uninstall packages", | |
| "# Delete lines to ignore packages entirely", | |
| "#", | |
| "" | |
| ] | |
| end | |
| # Write content to temp file and return the file | |
| def self.write_to_tempfile(content) | |
| Tempfile.new(['brew-upgrade-', '.txt']).tap do |file| | |
| file.write(content.join("\n")) | |
| file.flush | |
| end | |
| end | |
| # Open editor and return success status | |
| def self.open_editor(filepath) | |
| editor = ENV['EDITOR'] || 'vim' | |
| system(editor, filepath) | |
| end | |
| # Read and parse edited file | |
| def self.read_edited_file(filepath) | |
| File.readlines(filepath).map(&:chomp) | |
| end | |
| # Filter lines by prefix | |
| def self.filter_lines_by_prefix(lines, prefixes) | |
| lines | |
| .reject { |line| line.start_with?('#') || line.strip.empty? } | |
| .select { |line| prefixes.any? { |prefix| line.start_with?("#{prefix} ") } } | |
| end | |
| # Extract package name from line (first word after prefix) | |
| def self.extract_package_name(line) | |
| line.split[1] | |
| end | |
| # Extract packages for a given action | |
| def self.extract_packages_by_action(lines, prefixes) | |
| filter_lines_by_prefix(lines, prefixes).map { |line| extract_package_name(line) } | |
| end | |
| # Uninstall packages using brew | |
| def self.uninstall_packages(packages) | |
| return if packages.empty? | |
| puts "Uninstalling #{packages.size} package(s): #{packages.join(', ')}" | |
| puts "Running: brew uninstall #{packages.join(' ')}" | |
| system('brew', 'uninstall', *packages) | |
| end | |
| # Upgrade packages using brew | |
| def self.upgrade_packages(packages) | |
| return if packages.empty? | |
| puts "Upgrading #{packages.size} package(s): #{packages.join(', ')}" | |
| puts "Running: brew upgrade #{packages.join(' ')}" | |
| system('brew', 'upgrade', *packages) | |
| end | |
| # Main execution pipeline | |
| def self.run | |
| puts "Fetching outdated packages..." | |
| outdated = fetch_outdated_packages | |
| if outdated.empty? | |
| puts "All packages are up to date!" | |
| return | |
| end | |
| content = create_header + prefix_with_update(outdated) | |
| tempfile = write_to_tempfile(content) | |
| begin | |
| exit 1 unless open_editor(tempfile.path) | |
| edited_lines = read_edited_file(tempfile.path) | |
| # Extract packages for each action | |
| uninstall_packages = extract_packages_by_action(edited_lines, ['uninstall', 'remove', 'rm', 'del']) | |
| upgrade_packages_list = extract_packages_by_action(edited_lines, ['update', 'up', 'u']) | |
| # Run uninstalls first, then upgrades | |
| if uninstall_packages.empty? && upgrade_packages_list.empty? | |
| puts "No packages selected for upgrade or uninstall." | |
| return | |
| end | |
| uninstall_packages(uninstall_packages) | |
| upgrade_packages(upgrade_packages_list) | |
| puts "\nDone!" | |
| ensure | |
| tempfile.unlink | |
| end | |
| end | |
| end | |
| # Execute if run directly | |
| BrewUpgrade.run if __FILE__ == $PROGRAM_NAME |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment