diff options
author | James Turnbull <james@lovedthanlost.net> | 2009-02-10 02:14:55 +1100 |
---|---|---|
committer | James Turnbull <james@lovedthanlost.net> | 2009-02-10 02:14:55 +1100 |
commit | e52f962f44e98719212d788699ebaa6eb4d61904 (patch) | |
tree | 7a9e661d02778055493982264b8dfa06761c513e /tasks/rake | |
parent | 072643736fcfd37d3c2c42d6d9841f05ff391319 (diff) | |
download | facter-e52f962f44e98719212d788699ebaa6eb4d61904.tar.gz facter-e52f962f44e98719212d788699ebaa6eb4d61904.tar.xz facter-e52f962f44e98719212d788699ebaa6eb4d61904.zip |
Added Reductive Labs build library
Diffstat (limited to 'tasks/rake')
-rw-r--r-- | tasks/rake/redlabpackage.rb | 265 | ||||
-rw-r--r-- | tasks/rake/reductive.rb | 538 |
2 files changed, 803 insertions, 0 deletions
diff --git a/tasks/rake/redlabpackage.rb b/tasks/rake/redlabpackage.rb new file mode 100644 index 0000000..2de8005 --- /dev/null +++ b/tasks/rake/redlabpackage.rb @@ -0,0 +1,265 @@ +#!/usr/bin/env ruby + +# A raw platform for creating packages. + +require 'rbconfig' +require 'rake' +require 'rake/tasklib' + +# The PackageTask will create the following targets: +# +# [<b>:clobber_package</b>] +# Delete all the package files. This target is automatically +# added to the main clobber target. +# +# [<b>:repackage</b>] +# Rebuild the package files from scratch, even if they are not out +# of date. +# +# [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.tgz"</b>] +# Create a gzipped tar package (if <em>need_tar</em> is true). +# +# [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.tar.gz"</b>] +# Create a gzipped tar package (if <em>need_tar_gz</em> is true). +# +# [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.tar.bz2"</b>] +# Create a bzip2'd tar package (if <em>need_tar_bz2</em> is true). +# +# [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.zip"</b>] +# Create a zip package archive (if <em>need_zip</em> is true). +# +# Example: +# +# Rake::PackageTask.new("rake", "1.2.3") do |p| +# p.need_tar = true +# p.package_files.include("lib/**/*.rb") +# end +# +class Rake::RedLabPackageTask < Rake::TaskLib + # The different directory types we can manage. + DIRTYPES = { + :bindir => :bins, + :sbindir => :sbins, + :sitelibdir => :rubylibs + } + + # Name of the package (from the GEM Spec). + attr_accessor :name + + # Version of the package (e.g. '1.3.2'). + attr_accessor :version + + # Directory used to store the package files (default is 'pkg'). + attr_accessor :package_dir + + # The directory to which to publish packages and html and such. + attr_accessor :publishdir + + # The package-specific publishing directory + attr_accessor :pkgpublishdir + + # The Product name. Defaults to a capitalized version of the + # package name + attr_accessor :product + + # The copyright message. + attr_accessor :copyright + + # The vendor. + attr_accessor :vendor + + # The license file. Defaults to COPYING. + attr_accessor :license + + # The readme file. Defaults to README. + attr_accessor :readme + + # The description. + attr_accessor :description + + # The summary. + attr_accessor :summary + + # The directory in which to put the binaries. Defaults to the system + # default. + attr_accessor :bindir + + # The executables. + attr_accessor :bins + + # The directory in which to put the system binaries. Defaults to the + # system default. + attr_accessor :sbindir + + # The system binaries. + attr_accessor :sbins + + # The libraries. + attr_accessor :rubylibs + + # The directory in which to put Ruby libraries. Defaults to the + # system site_dir. + attr_accessor :sitelibdir + + # The URL for the package. + attr_accessor :url + + # The source for the package. + attr_accessor :source + + # Our operating system. + attr_reader :os + + # Add a required package. + def add_dependency(name, version = nil) + @requires[name] = version + end + + # Create the tasks defined by this task library. + def define + fail "Version required (or :noversion)" if @version.nil? + @version = nil if :noversion == @version + + directory pkgdest + file pkgdest => self.package_dir + + directory self.package_dir + + self.mkcopytasks + + self + end + + # Return the list of files associated with a dirname. + def files(dirname) + if @dirtypes.include?(dirname) + return self.send(@dirtypes[dirname]) + else + raise "Could not find directory type %s" % dirname + end + end + + # Create a Package Task with the given name and version. + def initialize(name=nil, version=nil) + # Theoretically, one could eventually add directory types here. + @dirtypes = DIRTYPES.dup + + @requires = {} + + @name = name + @version = version + @package_dir = 'pkg' + @product = name.capitalize + + @bindir = Config::CONFIG["bindir"] + @sbindir = Config::CONFIG["sbindir"] + @sitelibdir = Config::CONFIG["sitelibdir"] + + @license = "COPYING" + @readme = "README" + + yield self if block_given? + + define unless name.nil? + + # Make sure they've provided everything necessary. + %w{copyright vendor description}.each do |attr| + unless self.send(attr) + raise "You must provide the attribute %s" % attr + end + end + end + + # Make tasks for copying/linking all of the necessary files. + def mkcopytasks + basedir = pkgdest() + + tasks = [] + + # Iterate across all of the file locations... + @dirtypes.each do |dirname, filemethod| + tname = ("copy" + dirname.to_s).intern + + dir = self.send(dirname) + + reqs = [] + + # This is where we're putting the files. + targetdir = self.targetdir(dirname) + + # Make sure our target directories exist + directory targetdir + file targetdir => basedir + + # Get the file list and remove the leading directory. + files = self.files(dirname) or next + + reqs = [] + files.each do |sourcefile| + # The file without the basedir. This is necessary because + # files are created with the path from ".", but they often + # have 'lib' changed to 'site_ruby' or something similar. + destfile = File.join(targetdir, sourcefile.sub(/^\w+\//, '')) + reqs << destfile + + # Make sure the base directory is listed as a prereq + sourcedir = File.dirname(sourcefile) + destdir = nil + unless sourcedir == "." + destdir = File.dirname(destfile) + reqs << destdir + directory(destdir) + end + + # Now make the task associated with creating the object in + # question. + if FileTest.directory?(sourcefile) + directory(destfile) + else + file(destfile => sourcefile) do + if FileTest.exists?(destfile) + if File.stat(sourcefile) > File.stat(destfile) + rm_f destfile + safe_ln(sourcefile, destfile) + end + else + safe_ln(sourcefile, destfile) + end + end + + # If we've set the destdir, then list it as a prereq. + if destdir + file destfile => destdir + end + end + end + + # And create a task for each one + task tname => reqs + + # And then mark our task as a prereq + tasks << tname + end + + task :copycode => [self.package_dir, pkgdest] + + task :copycode => tasks do + puts "Finished copying" + end + end + + # Where we're copying a given type of file. + def targetdir(dirname) + File.join(pkgdest(), self.send(dirname)).sub("//", "/") + end + + private + + def package_name + @version ? "#{@name}-#{@version}" : @name + end + + def package_dir_path + "#{package_dir}/#{package_name}" + end +end diff --git a/tasks/rake/reductive.rb b/tasks/rake/reductive.rb new file mode 100644 index 0000000..2fbd2b4 --- /dev/null +++ b/tasks/rake/reductive.rb @@ -0,0 +1,538 @@ +#!/usr/bin/env ruby + +# The tasks associated with building Reductive Labs projects + +require 'rbconfig' +require 'rake' +require 'rake/tasklib' + +require 'rake/clean' +require 'rake/testtask' + +$features = {} + +begin + require 'rubygems' + require 'rake/gempackagetask' + $features[:gem] = true +rescue Exception + $features[:gem] = false + $stderr.puts "No Gems; skipping" + nil +end + +begin + require 'rdoc/rdoc' + $features[:rdoc] = true +rescue => detail + $features[:rdoc] = false + puts "No rdoc: %s" % detail +end + +if $features[:rdoc] + require 'rake/rdoctask' +end + +# Create all of the standard targets for a Reductive Labs project. +# NOTE: The reason so many of the rake tasks are generated, rather than being +# declared directly, is that they need information from the project instance. +# Any rake task with an instance variable (e.g., @name or @version) needs +# to have that variable assigned *before* the task is defined. Suckage. +class Rake::RedLabProject < Rake::TaskLib + # The project name. + attr_accessor :name + + # The project version. + attr_accessor :version + + # The directory to which to publish packages and html and such. + attr_accessor :publishdir + + # The package-specific publishing directory + attr_accessor :pkgpublishdir + + # Create a Gem file. + attr_accessor :mkgem + + # The hosts to run all of our tests on. + attr_accessor :testhosts + + # The summary of this project. + attr_accessor :summary + + # The description of this project. + attr_accessor :description + + # The author of this project. + attr_accessor :author + + # A Contact email address. + attr_accessor :email + + # The URL for the project. + attr_accessor :url + + # Where to get the source code. + attr_accessor :source + + # Who the vendor is. + attr_accessor :vendor + + # The copyright for this project + attr_accessor :copyright + + # The RubyForge project. + attr_accessor :rfproject + + # The list of files. Only used for gem tasks. + attr_writer :filelist + + # The directory in which to store packages. Defaults to "pkg". + attr_accessor :package_dir + + # The default task. Defaults to the 'alltests' task. + attr_accessor :defaulttask + + # The defined requirements + attr_reader :requires + + # The file containing the version string. + attr_accessor :versionfile + + # Print messages on stdout + def announce(msg = nil) + puts msg + end + + # Print messages on stderr + def warn(msg = nil) + $stderr.puts msg + end + + def add_dependency(name, version) + @requires[name] = version + end + + # Where we'll be putting the code. + def codedir + unless defined? @codedir + @codedir = File.join(self.package_dir, "#{@name}-#{@version}") + end + + return @codedir + end + + # Retrieve the current version from the code. + def currentversion + unless defined? @currentversion + ver = %x{ruby -Ilib ./bin/#{@name} --version}.chomp + if $? == 0 and ver != "" + @currentversion = ver + else + warn "Could not retrieve current version; using 0.0.0" + @currentversion = "0.0.0" + end + end + + return @currentversion + end + + # Define all of our package tasks. We just search through all of our + # defined methods and call anything that's listed as making tasks. + def define + self.methods.find_all { |method| method.to_s =~ /^mktask/ }.each { |method| + self.send(method) + } + end + + def egrep(pattern) + Dir['**/*.rb'].each do |fn| + count = 0 + open(fn) do |f| + while line = f.gets + count += 1 + if line =~ pattern + puts "#{fn}:#{count}:#{line}" + end + end + end + end + end + + # List all of the files. + def filelist + unless defined? @createdfilelist + # If they passed in a file list as an array, then create a FileList + # object out of it. + if defined? @filelist + unless @filelist.is_a? FileList + @filelist = FileList[@filelist] + end + else + # Use a default file list. + @filelist = FileList[ + 'install.rb', + '[A-Z]*', + 'lib/**/*.rb', + 'test/**/*.rb', + 'bin/**/*', + 'ext/**/*', + 'examples/**/*', + 'conf/**/*' + ] + end + @filelist.delete_if {|item| item.include?(".git")} + + @createdfilelist = true + end + + @filelist + end + + def has?(feature) + feature = feature.intern if feature.is_a? String + if $features.include?(feature) + return $features[feature] + else + return true + end + end + + def initialize(name, version = nil) + @name = name + + if ENV['REL'] + @version = ENV['REL'] + else + @version = version || self.currentversion + end + + @defaulttask = :alltests + @publishdir = "/opt/rl/docroots/reductivelabs.com/htdocs/downloads" + @pkgpublishdir = "#{@publishdir}/#{@name}" + + @email = "dev@reductivelabs.com" + @url = "http://reductivelabs.com/projects/#{@name}" + @source = "http://reductivelabs.com/downloads/#{@name}/#{@name}-#{@version}.tgz" + @vendor = "Reductive Labs, LLC" + @copyright = "Copyright 2003-2008, Reductive Labs, LLC. Some Rights Reserved." + @rfproject = @name + + @defaulttask = :package + + @package_dir = "pkg" + + @requires = {} + + @versionfile = "lib/#{@name}.rb" + + CLOBBER.include('doc/*') + + yield self if block_given? + define if block_given? + end + + def mktaskhtml + if $features[:rdoc] + Rake::RDocTask.new(:html) { |rdoc| + rdoc.rdoc_dir = 'html' + rdoc.template = 'html' + rdoc.title = @name.capitalize + rdoc.options << '--line-numbers' << '--inline-source' << + '--main' << 'README' + rdoc.rdoc_files.include('README', 'COPYING', 'CHANGELOG') + rdoc.rdoc_files.include('lib/**/*.rb') + CLEAN.include("html") + } + + # Publish the html. + task :publish => [:package, :html] do + puts Dir.getwd + sh %{cp -r html #{self.pkgpublishdir}/apidocs} + end + else + warn "No rdoc; skipping html" + end + end + + # Create a release task. + def mktaskrelease + desc "Make a new release" + task :release => [ + :prerelease, + :clobber, + :update_version, + :commit_newversion, + :trac_version, + :tag, # tag everything before we make a bunch of extra dirs + :html, + :package, + :publish + ] do + + announce + announce "**************************************************************" + announce "* Release #{@version} Complete." + announce "* Packages ready to upload." + announce "**************************************************************" + announce + end + end + + # Do any prerelease work. + def mktaskprerelease + # Validate that everything is ready to go for a release. + task :prerelease do + announce + announce "**************************************************************" + announce "* Making Release #{@version}" + announce "* (current version #{self.currentversion})" + announce "**************************************************************" + announce + + # Is a release number supplied? + unless ENV['REL'] + warn "You must provide a release number when releasing" + fail "Usage: rake release REL=x.y.z [REUSE=tag_suffix]" + end + + # Is the release different than the current release. + # (or is REUSE set?) + if @version == self.currentversion && ! ENV['REUSE'] + fail "Current version is #{@version}, must specify REUSE=tag_suffix to reuse version" + end + + # Are all source files checked in? + if ENV['RELTEST'] + announce "Release Task Testing, skipping checked-in file test" + else + announce "Checking for unchecked-in files..." + data = %x{git status} + unless data.include?("nothing to commit") + fail "git status is not clean ... do you have unchecked-in files?" + end + announce "No outstanding checkins found ... OK" + end + end + end + + # Create the task to update versions. + def mktaskupdateversion + task :update_version => [:prerelease] do + if @version == self.currentversion + announce "No version change ... skipping version update" + else + announce "Updating #{@versionfile} version to #{@version}" + open(@versionfile) do |rakein| + open("#{@versionfile}.new", "w") do |rakeout| + rakein.each do |line| + if line =~ /^(\s*)#{@name.upcase}VERSION\s*=\s*/ + rakeout.puts "#{$1}#{@name.upcase}VERSION = '#{@version}'" + else + rakeout.puts line + end + end + end + end + mv "#{@versionfile}.new", @versionfile + + end + end + + desc "Commit the new versions to SVN." + task :commit_newversion => [:update_version] do + if ENV['RELTEST'] + announce "Release Task Testing, skipping commiting of new version" + else + sh %{git commit -m "Updated to version #{@version}" #{@versionfile}} + end + end + end + + def mktasktrac_version + task :trac_version => [:update_version] do + tracpath = "/opt/rl/trac/#{@name}" + + unless FileTest.exists?(tracpath) + announce "No Trac instance at %s" % tracpath + else + output = %x{sudo trac-admin #{tracpath} version list}.chomp.split("\n") + versions = {} + output[3..-1].each do |line| + name, time = line.chomp.split(/\s+/) + versions[name] = time + end + + if versions.include?(@version) + announce "Version #{@version} already in Trac" + else + announce "Adding #{@name} version #{@version} to Trac" + date = [Time.now.year.to_s, + Time.now.month.to_s, + Time.now.day.to_s].join("-") + system("sudo trac-admin #{tracpath} version add #{@version} #{date}") + end + end + end + end + + # Create the tag task. + def mktasktag + desc "Tag all the files with the latest release number (REL=x.y.z)" + task :tag => [:prerelease] do + reltag = @version + announce "Tagging with [#{reltag}]" + + if ENV['RELTEST'] + announce "Release Task Testing, skipping tagging" + else + sh %{git tag #{reltag}} + end + end + end + + # Create the task for testing across all hosts. + def mktaskhosttest + desc "Test Puppet on each test host" + task :hosttest do + out = "" + TESTHOSTS.each { |host| + puts "testing %s" % host + cwd = Dir.getwd + file = "/tmp/#{@name}-#{host}test.out" + system("ssh #{host} 'cd git/#{@name}/test; sudo rake' 2>&1 >#{file}") + + if $? != 0 + puts "%s failed; output is in %s" % [host, file] + end + } + end + end + + def mktaskri + # Create a task to build the RDOC documentation tree. + + #Rake::RDocTask.new("ri") { |rdoc| + # #rdoc.rdoc_dir = 'html' + # #rdoc.template = 'html' + # rdoc.title = "Puppet" + # rdoc.options << '--ri' << '--line-numbers' << '--inline-source' << '--main' << 'README' + # rdoc.rdoc_files.include('README', 'COPYING', 'CHANGELOG') + # rdoc.rdoc_files.include('lib/**/*.rb', 'doc/**/*.rdoc') + #} + + if $features[:rdoc] + task :ri do |ri| + files = ['README', 'COPYING', 'CHANGELOG'] + Dir.glob('lib/**/*.rb') + puts "files are \n%s" % files.join("\n") + begin + ri = RDoc::RDoc.new + ri.document(["--ri-site"] + files) + rescue RDoc::RDocError => detail + puts "Failed to build docs: %s" % detail + return nil + rescue LoadError + puts "Missing rdoc; cannot build documentation" + return nil + end + end + else + warn "No rdoc; skipping ri." + end + end + + desc "Install the application using the standard install.rb script" + task :install do + ruby "install.rb" + end + + def mktaskdefault + if dtask = self.defaulttask + desc "Default task" + task :default => dtask + end + end + + desc "Run all unit tests." + task :alltests do + if FileTest.exists?("test/Rakefile") + sh %{cd test; rake} + else + Dir.chdir("test") do + Dir.entries(".").find_all { |f| f =~ /\.rb/ }.each do |f| + sh %{ruby #{f}} + end + end + end + end + + desc "List all ruby files" + task :rubyfiles do + puts Dir['**/*.rb'].reject { |fn| fn =~ /^pkg/ } + puts Dir['**/bin/*'].reject { |fn| fn =~ /svn|(~$)|(\.rb$)/ } + end + + desc "Look for TODO and FIXME tags in the code" + task :todo do + egrep "/#.*(FIXME|TODO|TBD)/" + end + + # This task requires extra information from the Rake file. + def mkgemtask + # ==================================================================== + # Create a task that will package the Rake software into distributable + # tar, zip and gem files. + if ! defined?(Gem) + puts "Package Target requires RubyGEMs" + else + spec = Gem::Specification.new { |s| + + #### Basic information. + + s.name = self.name + s.version = self.version + s.summary = self.summary + s.description = self.description + s.platform = Gem::Platform::RUBY + + #### Dependencies and requirements. + + # I'd love to explicitly list all of the libraries that I need, + # but gems seem to only be able to handle dependencies on other + # gems, which is, um, stupid. + self.requires.each do |name, version| + s.add_dependency(name, ">= #{version}") + end + + s.files = filelist.to_a + + #### Signing key and cert chain + #s.signing_key = '/..../gem-private_key.pem' + #s.cert_chain = ['gem-public_cert.pem'] + + #### Author and project details. + + s.author = [self.author] + s.email = self.email + s.homepage = self.url + s.rubyforge_project = self.rfproject + + yield s + } + + Rake::GemPackageTask.new(spec) { |pkg| + pkg.need_tar = true + } + + desc "Copy the newly created package into the downloads directory" + task :publish => [:package] do + puts Dir.getwd + sh %{cp pkg/#{@name}-#{@version}.gem #{self.publishdir}/gems} + sh %{gem generate_index -d #{self.publishdir}} + sh %{cp pkg/#{@name}-#{@version}.tgz #{self.pkgpublishdir}} + sh %{ln -sf #{@name}-#{@version}.tgz #{self.pkgpublishdir}/#{@name}-latest.tgz} + end + CLEAN.include("pkg") + end + end +end |