Skip to content

Instantly share code, notes, and snippets.

@pcreux
Created May 31, 2019 18:30
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pcreux/40bbdd8b7fde1156ace7e896c3a05875 to your computer and use it in GitHub Desktop.
Save pcreux/40bbdd8b7fde1156ace7e896c3a05875 to your computer and use it in GitHub Desktop.
Format 'bundle outdated' into a CSV file ordered by version delta
#!/usr/bin/env ruby
#
# Run `bundle outdated | format_bundle_outdated`
# to get a CSV file listing the columns below for all outdated gems.
COLUMNS = [ "name", "newest", "installed", "requested", "groups", "delta" ].join(",")
class Version < Struct.new(:major, :minor, :patch, :beta)
def self.build(string)
new(*string.split('.').map(&:to_i))
end
def to_s
[major, minor, patch, beta].compact.join('.')
end
def -(other)
major_delta = major.to_i - other.major.to_i
minor_delta = major_delta == 0 ? minor.to_i - other.minor.to_i : 0
patch_delta = major_delta == 0 && minor_delta == 0 ? patch.to_i - other.patch.to_i : 0
Version.new(
major_delta,
minor_delta,
patch_delta,
nil
)
end
end
rows = []
$stdin.each_line do |line|
if match = line.match(/\* (\S+) \(/)
name = match[1]
end
if match = line.match(/newest ([0-9.]+)/)
newest = match[1]
end
if match = line.match(/installed ([0-9.]+)/)
installed = match[1]
end
if match = line.match(/requested ([0-9.]+)/)
requested = match[1]
end
if match = line.match(/in groups "(\S+)"/)
groups = match[1].split(",")
end
if name
newest_v = Version.build(newest)
installed_v = Version.build(installed)
delta_v = newest_v - installed_v
rows << [
name,
newest,
installed,
requested,
groups,
delta_v.to_s
]
end
end
puts COLUMNS
rows.sort_by(&:last).each do |row|
puts row.join(",")
end
@pcreux
Copy link
Author

pcreux commented May 31, 2019

Sample output:

name,newest,installed,requested,groups,delta
factory_bot_rails,5.0.2,5.0.1,,,0.0.1
carmen,1.1.2,1.1.1,,default,0.0.1
unicorn,5.5.1,5.5.0,,,0.0.1
haml,5.1.1,5.1.0,,default,0.0.1
activerecord,5.2.3,5.1.6.2,,,0.1.0
useragent,0.16.10,0.4.12,,default,0.12.0
ffi,1.11.1,1.9.25,,,0.2.0
...

Oh, just noticed that the order is messed up for delta > 9 (ex: 0.1.0, 0.12.0, 0.2.0). I can live with that. Having one column per section (major, minor, patch) would solve that... might be harder to read though?

@franckverrot
Copy link

franckverrot commented May 31, 2019

Here you go. TL;DR: I've used Gem::Version to get a free starship operator. :-)

#!/usr/bin/env ruby
#
# Run `bundle outdated | ruby format_bundle_outdated.rb`
# to get a CSV file listing the columns below for all outdated gems.

COLUMNS =  [ "name", "newest", "installed", "requested", "groups", "delta" ].join(",")

class Version < Gem::Version
  def major; canonical_segments[0]; end
  def minor; canonical_segments[1] || 0; end
  def patch; canonical_segments[2] || 0; end
  def beta;  canonical_segments[3] || 0; end

  def -(other)
    major, minor, patch, beta = canonical_segments
    major_delta = major - other.major
    minor_delta = major_delta == 0 ? minor - other.minor : 0
    patch_delta = major_delta == 0 && minor_delta == 0 ? patch - other.patch : 0

    self.class.create("#{major_delta}.#{minor_delta}.#{patch_delta}")
  end
end

rows = []

$stdin.each_line do |line|
  if match = line.match(/\* (\S+) \(/)
    name = match[1]
  end

  if match = line.match(/newest ([0-9.]+)/)
    newest = match[1]
  end

  if match = line.match(/installed ([0-9.]+)/)
    installed = match[1]
  end

  if match = line.match(/requested ([0-9.]+)/)
    requested = match[1]
  end

  if match = line.match(/in groups "(\S+)"/)
    groups = match[1].split(",")
  end

  if name
    newest_v = Version.create(newest)
    installed_v = Version.create(installed)
    delta_v = newest_v - installed_v

    rows << [
      name,
      newest,
      installed,
      requested,
      groups,
      delta_v
    ]
  end
end

puts COLUMNS
rows.sort_by(&:last).each do |row|
  puts row.join(",")
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment