From: Florian Gross Date: 2005-03-26T12:19:50+09:00 Subject: Re: [ANN] Rake 0.5.0 Release --------------050408090007090309090104 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Ryan Davis wrote: > On Mar 25, 2005, at 3:49 PM, Florian Gross wrote: > >> 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? > > 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. --------------050408090007090309090104 Content-Type: text/plain; name="Rakefile" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="Rakefile" 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, unknown@unknown.tld" 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 --------------050408090007090309090104--