Skip to content

Instantly share code, notes, and snippets.

@movitto
Created November 8, 2012 03:07
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save movitto/4036394 to your computer and use it in GitHub Desktop.
gem rpm updater
#!/usr/bin/ruby
# gem rpm updater
#
# Will checkout an existing gem rpm from fedora,
# and update to the latest version found on http://rubygems.org
#
# Usage:
# gru.rb <gem_name>
#
# Licensed under the MIT License
# Written by Mo Morsi <mmorsi@redhat.com>
# Copyright (C) 2012 Red Hat
require 'curb'
require 'json'
require 'optparse'
require 'nokogiri'
#######################################################3
# Prettify the terminal output
module Colored
# Colored originally from: https://raw.github.com/defunkt/colored/master/lib/colored.rb
# MIT License: https://github.com/defunkt/colored/blob/master/LICENSE
extend self
COLORS = { 'black' => 30, 'red' => 31, 'green' => 32, 'yellow' => 33, 'blue' => 34, 'magenta' => 35, 'cyan' => 36, 'white' => 3}
EXTRAS = { 'clear' => 0, 'bold' => 1, 'underline' => 4, 'reversed' => 7}
COLORS.each do |color, value|
define_method(color) do colorize(self, :foreground => color) end
define_method("on_#{color}") do colorize(self, :background => color) end
COLORS.each do |highlight, value|
next if color == highlight ; define_method("#{color}_on_#{highlight}") do colorize(self, :foreground => color, :background => highlight) end
end
end
EXTRAS.each do |extra, value|
next if extra == 'clear' ; define_method(extra) do colorize(self, :extra => extra) end
end
define_method(:to_eol) do
tmp = sub(/^(\e\[[\[\e0-9;m]+m)/, "\\1\e[2K")
return "\e[2K" << self if tmp == self
tmp
end
def colorize(string, options = {})
colored = [color(options[:foreground]), color("on_#{options[:background]}"), extra(options[:extra])].compact * ''
colored << string << extra(:clear)
end
def colors ; @@colors ||= COLORS.keys.sort ; end
def extra(extra_name)
extra_name = extra_name.to_s ; "\e[#{EXTRAS[extra_name]}m" if EXTRAS[extra_name]
end
def color(color_name)
background = color_name.to_s =~ /on_/
color_name = color_name.to_s.sub('on_', '')
return unless color_name && COLORS[color_name]
"\e[#{COLORS[color_name] + (background ? 10 : 0)}m"
end
end unless Object.const_defined? :Colored
String.send(:include, Colored)
###############################################################
# read package/user name from command line
user = nil
gems = []
optparse = OptionParser.new do|opts|
opts.on('-n', '--name GEM', 'gem name' ) do |n|
gems << n
end
opts.on('-u', '--user USER', 'fedora user name' ) do |u|
user = u
end
opts.on('-h', '--help', 'display this screen' ) do
puts opts
exit
end
end
optparse.parse!
unless user.nil?
curl = Curl::Easy.new("https://admin.fedoraproject.org/pkgdb/users/packages/#{user}")
curl.http_get
packages = curl.body_str
gems += Nokogiri::HTML(packages).xpath("//a[@class='PackageName']").
select { |i| i.text =~ /rubygem-.*/ }.
collect { |i| i.text.gsub(/rubygem-/, '') }
end
if gems.empty?
puts "must specify a gem name or fedora user name!".red
exit 1
end
orig_dir = Dir.pwd
gems.each { |gem_name|
puts "Updating #{gem_name}".bold.green
Dir.chdir orig_dir
# TODO allow specifying version to update to as 2nd argument
rpm_name = "rubygem-#{gem_name}"
# assumes fedpkg is present
# TODO detect if directory exists, if so skip checkout (perhaps just pull?)
# TODO at some point use fedora api
unless File.directory? rpm_name
puts "Cloning fedora package".green
`fedpkg clone #{rpm_name}`
end
# cd into working directory
Dir.chdir rpm_name
if File.exists? 'dead.package'
puts "Dead package detected, skipping".red
next
end
# checkout the latest rawhide
# TODO allow other branches to be specified
`git checkout master`
`git reset HEAD~ --hard` # BE CAREFUL!
`git pull`
# grab the gem from rubygems
puts "Grabbing gem".green
spec = Curl::Easy.http_get("https://rubygems.org/api/v1/gems/#{gem_name}.json").body_str
specj = JSON.parse(spec)
# extract version out of it
version = specj["version"]
# download gem
puts "Downloading #{gem_name}-#{version}.gem".green
curl = Curl::Easy.new("https://rubygems.org/gems/#{gem_name}-#{version}.gem")
curl.follow_location = true
curl.http_get
gem = curl.body_str
File.open("#{gem_name}-#{version}.gem", "w") { |f| f.write gem }
# substitute version in spec file
puts "Updating spec file to version #{version}".green
`sed -i "s/Version.*/Version: #{version}/" #{rpm_name}.spec`
`sed -i "s/^Release.*/Release: 1%{?dist}/" #{rpm_name}.spec`
# build srpm
puts "Building srpm".green
`fedpkg srpm`
# attempt to build packages against rawhide w/ koji
puts "Building srpm in rawhide via koji".green
puts "koji build --scratch rawhide #{rpm_name}-#{version}-1.*.src.rpm".green
puts `koji build --scratch rawhide #{rpm_name}-#{version}-1.*.src.rpm`.blue
# TODO if build fails, spit out error, exit
# warn user if tests are not run (no check section)
has_check = open("#{rpm_name}.spec", "r") { |f| f.lines.find { |line| line.include?("%check") } }
puts "Warning: no %check section in spec, manually verify functionality!".bold.red unless has_check
# update sources and gitignore files
`md5sum #{gem_name}-#{version}.gem > sources`
File.open(".gitignore", "w") { |f| f.write "#{gem_name}-#{version}.gem" }
# TODO also need to add a spec changelog message
# git add spec, git commit w/ message
`git add #{rpm_name}.spec sources .gitignore`
#`git add #{gem_name}-#{version}.gem`
`git commit -m 'updated to #{version}'`
# spit out command to push the package to fedora,
# build it against koji, and submit it to bodhi
puts "#{gem_name} commit complete".green
}
puts "Push commit to fedora with: git push".blue
puts "Build and tag official rpms with: koji build".blue
#puts "Submit updates via: https://admin.fedoraproject.org/updates".blue # uneeded for rawhide
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment