Ryan said:
I am!!! I was just gonna write this soon.
GIMME!
I've attached the whole file (used for ruby-breakpoint, BTW) as that
particular task depends on the presence of a few constants and other
data. You'll probably want to refactor that a bit so that it works in
your Rakefile as well, but the basic logic should still apply.
The task that does the RubyForge file publishing is
ublish_files.
If you're going to refactor this into a general task it would be
wonderful if you could contribute it to Jim, by the way.
require 'rake'
require 'find'
readme = File.read("README")
Release = (readme[/^= (.+) README$/, 1] || "unknown").tr(" ", "-")
Name = Release[/\D+/].sub(/\-+$/, "") || "unknown"
Version = Release[/[\d.]+/] || "unknown"
author_string = readme[/== Author\s+(.+)/, 1] || "unknown, (e-mail address removed)"
AuthorName, AuthorMail = author_string.split(", ")
RubyVersion = readme[/== Requirements.+?\* Ruby (.+?)$/m, 1] || "0.0.0"
Description = (readme[/README\s+(.+?)\n\n/m, 1] || "unknown").gsub(/\s+/, " ")
Summary = Description[/^.+?\./] || "unknown"
DocFiles = %w(README NEWS TODO COPYING GPL)
RDocFiles = DocFiles - %w(GPL)
RDocOpts = ["--inline-source", "--line-numbers",
"--title", Name
]
AdditionalFiles = DocFiles + %w(setup.rb)
VersionFile = MainFile = File.join("lib", Name.sub("ruby-", "") + ".rb")
RubyForgeProject = Name
RubyForgeUser = "flgr"
Homepage = "
http://#{RubyForgeProject}.rubyforge.org/"
task :none
if File.exist?("test") then
task :default => [:unit_test]
desc "Run all the unit tests"
task :unit_test do
ruby "test/tc_all.rb"
end
desc "Run the unit tests and create a coverage report"
task :coverage => ["test/coverage"]
directory "test/coverage"
file "test/coverage" => ["lib", "test"] do
sh "rcov.bat test/tc_all.rb -o test/coverage"
end
else
task :unit_test do
end
task :test do
end
task :coverage do
end
end
unless File.exist?("bin") then
task :bin do
end
end
desc "Publish a new release."
task
ublish => ["upload", "publish_files"]
desc "Upload everything to the web."
task :upload => ["upload_doc", "upload_pages", "upload_release"]
desc "Upload the documentation to the web."
task :upload_doc => ["doc"] do
if RubyForgeProject then
path = "/var/www/gforge-projects/#{RubyForgeProject}"
sh "pscp -scp -r -C -q doc #{RubyForgeUser}@rubyforge.org:#{path}"
end
end
desc "Upload the release to the web."
task :upload_release => "release/#{Release}" do
if RubyForgeProject then
path = "/var/www/gforge-projects/#{RubyForgeProject}/release/#{Release}/"
sh "pscp -scp -r -C -q release/#{Release}/ #{RubyForgeUser}@rubyforge.org:#{path}"
end
end
desc "Upload the web pages to the web."
task :upload_pages => ["web"] do
if RubyForgeProject then
path = "/var/www/gforge-projects/#{RubyForgeProject}"
sh "pscp -scp -r -C -q web/* #{RubyForgeUser}@rubyforge.org:#{path}"
end
end
desc "Publish the release files to RubyForge."
task
ublish_files => [:release] do
files = ["md5sum", "gem", "tgz", "zip"].map { |ext| "release/#{Release}.#{ext}" }
if RubyForgeProject then
require 'net/http'
require 'open-uri'
changes = ""
if File.exist?("NEWS") then
changes_re = /^== \s+ #{Regexp.quote(Name)} \s+ #{Regexp.quote(Version)} \s*
(.+?) (?:==|\Z)/mx
changes = File.read("NEWS")[changes_re, 1] || ""
end
project_uri = "
http://rubyforge.org/projects/#{RubyForgeProject}/"
project_data = open(project_uri) { |data| data.read }
group_id = project_data[/[?&]group_id=(\d+)/, 1]
raise "Couldn't get group id" unless group_id
# This echos password to shell which is a bit sucky
print "#{RubyForgeUser}@rubyforge.org's password: "
password = STDIN.gets.chomp
login_response = Net::HTTP.start("rubyforge.org", 80) do |http|
data = [
"login=1",
"form_loginname=#{RubyForgeUser}",
"form_pw=#{password}"
].join("&")
http.post("/account/login.php", data)
end
cookie = login_response["set-cookie"]
raise "Login failed" unless cookie
headers = { "Cookie" => cookie }
release_uri = "
http://rubyforge.org/frs/admin/?group_id=#{group_id}"
release_data = open(release_uri, headers) { |data| data.read }
package_id = release_data[/[?&]package_id=(\d+)/, 1]
raise "Couldn't get package id" unless package_id
first_file = true
release_id = ""
files.each do |filename|
basename = File.basename(filename)
file_ext = File.extname(filename)
file_data = File.open(filename, "rb") { |file| file.read }
puts "Releasing #{basename}..."
release_response = Net::HTTP.start("rubyforge.org", 80) do |http|
release_date = Time.now.strftime("%Y-%m-%d %H:%M")
type_map = {
".zip" => "3000",
".tgz" => "3110",
".gz" => "3110",
".gem" => "1400",
".md5sum" => "8100"
}; type_map.default = "9999"
type = type_map[file_ext]
boundary = "rubyqMY6QN9bp6e4kS21H4y0zxcvoor"
query_hash = if first_file then
{
"group_id" => group_id,
"package_id" => package_id,
"release_name" => Release,
"release_date" => release_date,
"type_id" => type,
"processor_id" => "8000", # Any
"release_notes" => "",
"release_changes" => changes,
"preformatted" => "1",
"submit" => "1"
}
else
{
"group_id" => group_id,
"release_id" => release_id,
"package_id" => package_id,
"step2" => "1",
"type_id" => type,
"processor_id" => "8000", # Any
"submit" => "Add This File"
}
end
query = "?" + query_hash.map do |(name, value)|
[name, URI.encode(value)].join("=")
end.join("&")
data = [
"--" + boundary,
"Content-Disposition: form-data; name=\"userfile\"; filename=\"#{basename}\"",
"Content-Type: application/octet-stream",
"Content-Transfer-Encoding: binary",
"", file_data, ""
].join("\x0D\x0A")
release_headers = headers.merge(
"Content-Type" => "multipart/form-data; boundary=#{boundary}"
)
target = first_file ? "/frs/admin/qrs.php" : "/frs/admin/editrelease.php"
http.post(target + query, data, release_headers)
end
if first_file then
release_id = release_response.body[/release_id=(\d+)/, 1]
raise("Couldn't get release id") unless release_id
end
first_file = false
end
end
end
desc "Make release for #{Release} (adjust in README)"
task :release => ["clean", "coverage", "signatures"]
desc "Delete generated data"
task :clean do
rm_r "test/coverage" if File.exist?("test/coverage")
rm_r "doc" if File.exist?("doc")
rm(Dir.glob("release/#{Release}.*"))
end
desc "Generate the documentation"
task "doc" do
args = RDocOpts.join(" ")
sh "rdoc.bat #{args} #{RDocFiles.join(" ")} lib"
end
task :signatures => "release/#{Release}.md5sum"
directory "release"
file "release/#{Release}.md5sum" => ["release/#{Release}.zip",
"release/#{Release}.tgz", "gem"] do
target = "#{Release}.md5sum"
rm target if File.exist?(target)
Dir.chdir("release") do
files = Dir.glob("#{Release}.*")
sh "md5sum #{files.join(" ")} > #{target}"
sh "unix2dos #{target}"
end
end
directory "release"
file "release/#{Release}.zip" => ["release/#{Release}"] do
target = "release/#{Release}.zip"
rm target if File.exist?(target)
Dir.chdir("release") do
sh "zip -9 -r #{Release}.zip #{Release}"
end
end
directory "release"
file "release/#{Release}.tgz" => ["release/#{Release}"] do
target = "release/#{Release}.tgz"
rm target if File.exist?(target)
Dir.chdir("release") do
sh "tar -czvf #{Release}.tgz #{Release}"
end
end
task :gem => ["release/#{Release}.gem"]
directory "release"
file "release/#{Release}.gem" => ["release/#{Release}"] do
target = "release/#{Release}.gem"
rm target if File.exist?(target)
Dir.chdir("release/#{Release}") do
require "rubygems"
require "rubygems/builder"
spec = Gem::Specification.new do |s|
s.name = Name
s.version = Version
s.platform = Gem:
latform::RUBY
s.required_ruby_version = RubyVersion
s.summary = Summary
s.description = Description
s.files = Dir.glob("**/*")
s.require_path = "lib"
s.autorequire = File.basename(MainFile)
s.executables += Dir.entries("bin").find_all { |f| File.file? "bin/#{f}" }
s.test_file = "test/tc_all.rb" if File.exist?("test")
s.has_rdoc = true
s.extra_rdoc_files = RDocFiles
s.rdoc_options = RDocOpts
s.author = AuthorName
s.email = AuthorMail
s.homepage = Homepage if Homepage
s.rubyforge_project = RubyForgeProject if RubyForgeProject
end
Gem::Builder.new(spec).build
end
mv "release/#{Release}/#{Release}.gem", "release/#{Release}.gem"
end
directory "release/#{Release}"
file "release/#{Release}" => ["lib", "bin", "test", "doc"] do
target = "release/#{Release}"
rm_r target if File.exist?(target)
mkdir target
["lib", "bin", "test", "doc"].each do |dir|
Find.find(dir) do |path|
if File.directory?(path) then
if File.split(path).last.downcase == ".svn" then
Find.prune
else
mkdir File.join(target, path)
end
else
cp path, File.join(target, path)
end
end
end
# Adjust Version
main_file = File.join(target, VersionFile)
data = File.read(main_file)
File.open(main_file, "w") do |file|
new_data = data.sub("Version = current_version", "Version = #{Version.inspect}")
file.write(new_data)
end
AdditionalFiles.each do |file|
cp file, File.join(target, file)
end
# Convert bin/ files to unix line format
Dir[File.join(target, "bin", "*")].each do |file|
sh "dos2unix #{file}"
end
# Generate Manifest
File.open(File.join(target, "Manifest"), "w") do |file|
files = Dir.chdir(target) { Dir.glob("**/*") }
file.write(files.join("\n"))
end
end