[ANN] Rake 0.5.0 Release

J

Jim Weirich

= Rake 0.5.0 Released

It has been a long time in coming, but we finally have a new version
of Rake available.

== Changes

* Fixed bug where missing intermediate file dependencies could cause
an abort with --trace or --dry-run. (Brian Chandler)

* Recursive rules are now supported (Tilman Sauerbeck).

* Added tar.gz and tar.bz2 support to package task (Tilman Sauerbeck).

* Added warning option for the Test Task (requested by Eric Hodel).

* The jamis rdoc template is only used if it exists.

* Added fix for Ruby 1.8.2 test/unit and rails problem.

* Added contributed rake man file. (Jani Monoses)

* Fixed documentation that was lacking the Rake module name (Tilman
Sauerbeck).

== What is Rake

Rake is a build tool similar to the make program in many ways. But
instead of cryptic make recipes, Rake uses standard Ruby code to
declare tasks and dependencies. You have the full power of a modern
scripting language built right into your build tool.

== Availability

The easiest way to get and install rake is via RubyGems ...

gem install rake (you may need root/admin privileges)

Otherwise, you can get it from the more traditional places:

Home Page:: http://rake.rubyforge.org/
Download:: http://rubyforge.org/project/showfiles.php?group_id=50

== Thanks

Lots of people provided input to this release. Thanks to Tilman
Sauerbeck for numerous patches, documentation fixes and suggestions.
And for also pushing me to get this release out. Also, thanks to
Brian Chandler for the finding and fixing --trace/dry-run fix. That
was an obscure bug. Also to Eric Hodel for some good suggestions.

-- Jim Weirich
 
P

Phlip

Jim said:
= Rake 0.5.0 Released

It has been a long time in coming, but we finally have a new version
of Rake available.

Did you improve the introductory documentation?

I tried to use Rake once, and I could not get it to execute a command if a
file had changed. That could just be me.
 
J

Jim Weirich

On Friday 25 March 2005 06:34 pm, Phlip wrote:

Hi Phlip!
Did you improve the introductory documentation?

Only minor tweaks to the docs this time around.
I tried to use Rake once, and I could not get it to execute a command if a
file had changed. That could just be me.

Hmmm ... where did you have problems? I'm always looking for ways to improve
rake, including the documentation.
 
F

Florian Gross

Jim said:
= Rake 0.5.0 Released

It has been a long time in coming, but we finally have a new version
of Rake available.

Thanks a lot for this wonderful tool.

I have code in my Rakefile for uploading releases to RubyForge so that
they will correctly appear under the project's file release page.
(E.g. http://rubyforge.org/frs/?group_id=559)

I've however not factored this out into a separate task. Would you still
be interested in this?
 
F

Florian Gross

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 :publish_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 :publish => ["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 :publish_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::platform::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
 
P

Phlip

Jim said:
Hmmm ... where did you have problems? I'm always looking for ways to improve
rake, including the documentation.

Here:

'file.exe' => ['file.cpp', 'file.h']
`cc file.cpp`

Run the cc line if .cpp or .h changed.

All documentation everywhere has this problem. The author takes something
for granted and the reader misses it.

I went with this:

if make('file.exe', ['file.cpp', 'file.h']) then
`cc file.cpp`
end

make() just reports true if any of its right arguments have a greater file
mod time than its first argument. The problem with that technique is it uses
no elaborate blocks or => marks, or Rake.
 
J

Jim Weirich

Jim said:
Hmmm ... where did you have problems?

Here:
'file.exe' => ['file.cpp', 'file.h']
`cc file.cpp`

Run the cc line if .cpp or .h changed.
I went with this:

if make('file.exe', ['file.cpp', 'file.h']) then
`cc file.cpp`
end
make() just reports true if any of its right arguments have a greater file
mod time than its first argument. The problem with that technique is it
uses no elaborate blocks or => marks, or Rake.

If that's all you need, go for it. The original version of Rake was under 100
lines of code, so obviously plain old Ruby is very close to solving the
problem without using Rake.

But, your simple example can be rendered in Rake as ...

file "file.exe" => ['file.cpp', 'file.h'] do
sh %{cc file.cpp -o file.exe}
end
 
L

Lyle Johnson

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.

Oh my. First of all, congratulations to Florian for figuring out how
to maneuver through all of the HTML forms to automate this task. ;)

Having said that, though, this seems to highlight the fact that we
could really use some kind of simple (and more direct) API for making
file releases at RubyForge. Here is one support request that addresses
the problem:

http://rubyforge.org/tracker/index.php?func=detail&aid=531&group_id=5&atid=104

and there may be others.
 
P

Phlip

Jim said:
But, your simple example can be rendered in Rake as ...

file "file.exe" => ['file.cpp', 'file.h'] do
sh %{cc file.cpp -o file.exe}
end

Is that the complete Rakefile?
 
J

Jim Weirich

Jim said:
But, your simple example can be rendered in Rake as ...

file "file.exe" => ['file.cpp', 'file.h'] do
sh %{cc file.cpp -o file.exe}
end

Is that the complete Rakefile?

Complete enough to build the file.exe upon request (e.g. "rake file.exe" from
the command line). If you wish to make file.exe the default target (so that
a plain "rake" one the command line will work), you can add the following
line ...

task :default => ["file.exe"]
 
P

phlip2005

Jim said:
file "file.exe" => ['file.cpp', 'file.h'] do
sh %{cc file.cpp -o file.exe}
end

Is that the complete Rakefile?

Complete enough to build the file.exe upon request (e.g. "rake file.exe" from
the command line). If you wish to make file.exe the default target (so that
a plain "rake" one the command line will work), you can add the following
line ...

task :default => ["file.exe"]

You need someone as brain-damaged as me to help you improve the manual.
I couldn't make that connection from reading the intro, and the stuff
for 'task' and 'file'.

The next time I need my make() function I will instead use Rake, to
force it to grow on me.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,999
Messages
2,570,243
Members
46,838
Latest member
KandiceChi

Latest Threads

Top