Tags

redhat
employment
ripple
interfaces
ncurses
ruby
refs
filesystems
retro gaming
raspberry pi
sinatra
3d printing
nethack
gcc
compiler
fedora
virtfs
project
gaming
vim
grep
sed
aikido
philosophy
splix
android
lvm
storage
bitcoin
projects
sig315
miq
db
polisher
meditation
hopex
conferences
omega
simulator
bundler_ext
rubygems
book review
google code in
isitfedoraruby
svn
gsoc
design patters
jsonrpc
rjr
aeolus
ohiolinuxfest
rome
europe
travel
brno
gtk
python
puppet
conference
fudcon
snap
html5
tips
ssh
linux
hardware
libvirt
virtualization
engineering expo
cloud
rpm
yum
rake
redmine
plugins
screencasting
jruby
fosscon
pidgin
gnome-shell
distros
notacon
presentation
rails
deltacloud
apache
qmf
passenger
syrlug
hackerspace
music
massive attack
crypto
backups
vnc
xsd
rxsd
x3d
mercurial
ovirt
qpid
webdev
haikus
poetry
legaleese
jquery
selenium
testing
xpath
git
sshfs
svg
ldap
autotools
pygtk
xmlrpc
slackware

Sep 5 2011 rpm yum rake

RPM and Yum Rake Tasks

As part of our dev and release cycle for aeolus we build alot of rpms and yum repositories.

To help with this process, especially for the aeolus puppet configuration recipes, we whipped up a couple of rake tasks to create rpms and yum repositories.

The latest versions of the tasks can be found here and can simply be included in your Rakefile as such:

require 'rubygems'
require 'rake/rpmtask'
require 'rake/yumtask'

CURRENT_DIR  = File.dirname(__FILE__)
YUM_REPO     = "#{CURRENT_DIR}/repo"
RPM_SPEC     = "my-package.spec"

# Build the rpm
rpm_task =
Rake::RpmTask.new(RPM_SPEC) do |rpm|
  rpm.need_tar = true
  rpm.package_files.include("bin/*", "recipes/**/*")
  rpm.topdir = "#{RPMBUILD_DIR}"
end

# Construct yum repo
Rake::YumTask.new(YUM_REPO) do |repo|
  repo.rpms << rpm_task.rpm_file
end

And without further ado, here is the rpm task

# Define a package task library to aid in the definition of RPM
# packages.

require 'rubygems'
require 'rake'
require 'rake/packagetask'

require 'rbconfig' # used to get system arch

module Rake

  # Create a package based upon a RPM spec.
  # RPM packages, can be produced by this task.
  class RpmTask < PackageTask
    # RPM spec containing the metadata for this package
    attr_accessor :rpm_spec

    # RPM build dir
    attr_accessor :topdir

    # Include extra_release information in the rpm
    attr_accessor :include_extra_release

    def initialize(rpm_spec)
      init(rpm_spec)
      yield self if block_given?
      define if block_given?
    end

    def init(rpm_spec)
      @include_extra_release = true
      @rpm_spec = rpm_spec

      # parse this out of the rpmbuild macros,
      # not ideal but better than hardcoding this
      File.open('/etc/rpm/macros.dist', "r") { |f|
        f.read.scan(/%dist\s*\.(.*)\n/)
        @distro = $1
      }

      # Parse rpm name / version out of spec
      # hacky way to do this for now
      #   (would be nice to implement a full blown rpm spec parser for ruby)
      File.open(rpm_spec, "r") { |f|
        contents = f.read
        @name    = contents.scan(/\nName: .*\n/).first.split.last
        @version = contents.scan(/\nVersion: .*\n/).first.split.last
        @release = contents.scan(/\nRelease: .*\n/).first.split.last
        @release.gsub!("%{?dist}", ".#{@distro}")
        @arch    =  contents.scan(/\nBuildArch: .*\n/) # TODO grab local arch if not defined
        if @arch.nil?
          @arch = Config::CONFIG["target_cpu"] # hoping this will work for all cases,
                                               # can just run the 'arch' cmd if we want
        else
          @arch = @arch.first.split.last
        end
      }
      super(@name, @version)

      @rpmbuild_cmd = 'rpmbuild'
    end

    def define
      super

      directory "#{@topdir}/SOURCES"
      directory "#{@topdir}/SPECS"

      desc "Build the rpms"
      task :rpms, [:include_extra_release] => [rpm_file]

      # FIXME properly determine :package build artifact(s) to copy to sources dir
      file rpm_file, [:include_extra_release] => [:package, "#{@topdir}/SOURCES", "#{@topdir}/SPECS"] do |t,args|
        @include_extra_release = args.include_extra_release != "false"
        git_head = `git log -1 --pretty=format:%h`
        extra_release = "." + Time.now.strftime("%Y%m%d%k%M%S").gsub(/\s/, '') + "git" + "#{git_head}"
        cp "#{package_dir}/#{@name}-#{@version}.tgz", "#{@topdir}/SOURCES/"
        cp @rpm_spec, "#{@topdir}/SPECS"
        sh "#{@rpmbuild_cmd} " +
           "--define '_topdir #{@topdir}' " +
           "--define 'extra_release #{@include_extra_release ? extra_release : ''}' " +
           "-ba #{@rpm_spec}"
      end
    end

    def rpm_file
      # at some point we should support all a spec's subpackages as well
      "#{@topdir}/RPMS/#{@arch}/#{@name}-#{@version}-#{@release}.#{@arch}.rpm"
    end
  end
end

And here is the yum task

# Define a package task library to aid in the definition of YUM
# repos.

require 'rubygems'
require 'rake'

module Rake

  # Create a yum repo with specified rpms
  class YumTask < TaskLib
    # Yum repository location which to build
    attr_accessor :yum_repo

    # RPMs to pull into yum repo
    attr_accessor :rpms

    def initialize(yum_repo)
      init(yum_repo)
      yield self if block_given?
      define if block_given?
    end

    def init(yum_repo)
      @yum_repo = yum_repo
      @createrepo_cmd = 'createrepo'
      @rpms = []
    end

    def define
      desc "Build the yum repo"
      task :create_repo => @rpms do
        @rpms.each { |rpm|
          rpmc = rpm.split('.')
          arch = rpmc[rpmc.size-2]
          arch_dir = @yum_repo + "/" + arch
          FileUtils.mkdir_p arch_dir unless File.directory? arch_dir
          cp_r rpm, "#{@yum_repo}/#{arch}"
        }
        sh "#{@createrepo_cmd} -v #{@yum_repo}"
      end
    end
  end
end

Have at it!