require "enumerator" require 'reap/task' require "reap/vendor/http-access2" # ___ _ _____ _ # | _ \___| |___ __ _ ___ ___ |_ _|_ _ __| |__ # | / -_) / -_) _` (_- [:gem] do # Rake::XForge::Release.new(project) {} # end # # The previous example will use defaults where it can. It will prompt # you for your xForge user name and password before it uploads all # gems under the pkg folder and creates a RubyForge release. # # While defaults are nice, you may want a little more control. You can # specify additional attributes: # # * #user_name # * #password # * #changes_file # * #version # * #files # * #release_name # * #release_notes # * #release_changes # * #package_name # # Example: # project = MetaProject::Project::XForge::RubyForge.new('xforge') # task :release => [:gem] do # release_files = FileList[ 'pkg/*.gem', 'CHANGES' ] # # Rake::XForge::Release.new(project) do |xf| # # Never hardcode user name and password in the Rakefile! # xf.user_name = ENV['RUBYFORGE_USER'] # xf.password = ENV['RUBYFORGE_PASSWORD'] # xf.files = release_files.to_a # xf.release_name = "XForge 0.1" # end # # This can be invoked from the command line: # # rake release RUBYFORGE_USER=myuser \ # RUBYFORGE_PASSWORD=mypassword # # If you don't like blocks, you can do like this: # # project = MetaProject::Project::XForge::RubyForge.new('xforge') # task :release => [:gem] do # xf = Rake::XForge::Release.new(project) # ... # Set additional attributes # xf.execute # end class Reap::Release < Reap::Task section_required true task_desc "Release distribution files." task_help %{ reap release Release distribution to Rubyforge, or other GForge based service. host URL of host service username Username of host service project Project name at host package Package name groupid Group id number architecture Architecture (Any, i386, PPC, etc.) release Release name private Private release? changelog Change log file notelog Release notes file dir Distribution directory exclude Distribution types to exclude } task_attr :rel #attr_accessor :project, :version #attr_accessor :host, :username, :password #attr_accessor :package, :packageid, :groupid, :private, :processor #attr_accessor :name, :changes, :notes, :changelog, :notelog #attr_accessor :cookiejar def init #rel.version ||= master.date rel.host ||= 'rubyforge.org' rel.host.chomp!('/') rel.username ||= master.rubyforge.username #rel.password ||= master.rubyforge.password rel.project ||= master.rubyforge.project || master.name rel.package ||= master.rubyforge.package #rel.packageid ||= master.rubyforge.packageid rel.groupid ||= master.rubyforge.groupid rel.private ||= false rel.processor ||= 'Any' rel.date ||= Time::now.strftime('%Y-%m-%d %H:%M') rel.exclude ||= [] rel.exclude << 'tar.gz' if rel.exclude.include?( 'tgz' ) rel.exclude << 'tgz' if rel.exclude.include?( 'tar.gz' ) rel.exclude << 'tar.bz2' if rel.exclude.include?( 'tbz' ) rel.exclude << 'tbz' if rel.exclude.include?( 'tar.bz2' ) rel.cookie_jar ||= File::join(File::expand_path("~"), ".rubyforge.cookie_jar") # Do not inherit rel.dir = section.dir || master.project.dir rel.release = section.release || master.version || rel.date end # Run release task. def run abort "missing field -- package" unless rel.package #abort "missing field -- packageid" unless rel.packageid abort "missing field -- groupid" unless rel.groupid # add more... # case rel.host # when 'rubyforge', 'rubyforge.org' # else # puts %{Unrecognized release host '#{rel.host}'. Skipped.} # skip = true # end puts "Reap is preparing release ..." rtypes = [ 'tgz', 'tbz', 'tar.gz', 'tar.bz2', 'deb', 'gem', 'ebuild' ] rtypes -= rel.exclude rtypes = rtypes.collect { |rt| Regexp.escape( rt ) } re_rtypes = Regexp.new( '[.](' << rtypes.join('|') << ')$' ) dir = File.join( rel.dir, "#{rel.name}-#{rel.version}" ) files = Dir.entries(dir).select { |f| f =~ re_rtypes or f == 'PKGBUILD' } files = files.collect { |f| File.join( rel.dir, f ) } if files.empty? puts "No files to release at #{dir}." exit -1 end # ask for password print "Password for #{rel.username}: " until passwd = $stdin.gets.strip ; sleep 1 ; end @password = passwd login { unless package? exit 0 create_package end if release? exit 0 files.each do |f| remove_file( f ) if file?( f ) add_file( f ) end else exit 0 add_release( files.unshift ) files.each { |f| add_file( f ) } end } end private FILETYPES = { ".deb" => 1000, ".rpm" => 2000, ".zip" => 3000, ".bz2" => 3100, ".gz" => 3110, ".src.zip" => 5000, ".src.bz2" => 5010, ".src.gz" => 5020, ".src.rpm" => 5100, ".src" => 5900, ".jpg" => 8000, ".txt" => 8100, ".text" => 8100, ".htm" => 8200, ".html" => 8200, ".pdf" => 8300, ".oth" => 9999, ".ebuild" => 1300, ".exe" => 1100, ".dmg" => 1200, ".tar.gz" => 5000, ".tgz" => 5000, ".gem" => 1400, ".pgp" => 8150, ".sig" => 8150, } PROCESSORS = { "i386" => 1000, "IA64" => 6000, "Alpha" => 7000, "Any" => 8000, "PPC" => 2000, "MIPS" => 3000, "Sparc" => 4000, "UltraSparc" => 5000, "Other" => 9999, } # login def login( &block ) # login page = "/account/login.php" method = "post_content" form = { "return_to" => "", "form_loginname" => rel.username, "form_pw" => @password, "login" => "Login" } http_transaction( page, method, form ) # do whatever block.call # logout page = "/account/logout.php" method = "" #"post_content" form = {} http_transaction( page, method, form ) end # Package exists? def package? page = "/frs/" method = "post_content" form = { "group_id" => rel.groupid } scrape = http_transaction( page, method, form ) restr = '' restr << Regexp.escape( rel.package ) restr << '\s*' restr << Regexp.escape( %{ rel.groupid, "package_name" => rel.package, "func" => "add_package", "is_public" => (rel.private ? 0 : 1), "submit" => "Create This Package" } http_transaction( page, method, form ) end # Release exits? def release? page = "/frs/admin/showreleases.php" method = "post_content" form = { "package_id" => rel.packageid, "group_id" => rel.groupid } scrape = http_transaction( page, method, form ) restr = '' restr << Regexp.escape( %{"editrelease.php?group_id=#{rel.groupid}} ) restr << Regexp.escape( %{&package_id=#{rel.packageid}} ) restr << Regexp.escape( %{&release_id=} ) restr << '(\d+)' restr << Regexp.escape( %{">#{rel.release}} ) re = Regexp.new( restr ) md = re.match( scrape ) if md rel.releaseid = md[1] end end # Add a new release. def add_release( userfile ) page = "/frs/admin/qrs.php" method = "post_content" type_id = rel.type || userfile[%r|\.[^\./]+$|] type_id = FILETYPES[type_id] proc_id = PROCESSORS[rel.processor] # how to use these? notes = rel.notes ? rel.notes : ( rel.notelog ? open(rel.notelog) : nil ) changes = rel.changes ? rel.changes : ( rel.changelog ? open(rel.changelog) : nil ) userfile = open(rel.userfile) preformatted = '1' form = { "group_id" => rel.groupid, "package_id" => rel.packageid, "release_name" => rel.name, "release_date" => rel.date, "type_id" => type_id, "processor_id" => proc_id, "preformatted" => preformatted, "userfile" => userfile, "submit" => "Release File" } boundary = Array::new(8){ "%2.2d" % rand(42) }.join('__') extheader = { 'content-type'=>"multipart/form-data; boundary=___#{ boundary }___" } http_transaction( page, method, form, extheader ) end # Does file exist? # Note this is a little bit fragile. # If two releases have the same exact file name in them # there could be a problem --that's probably not likely, # maybe even impossible, but as of yet, I can't yet rule it out. def file?( file ) page = "/frs/" method = "post_content" form = { "group_id" => rel.groupid } scrape = http_transaction( page, method, form ) restr = '' restr << Regexp.escape( rel.package ) restr << '\s*' restr << Regexp.escape( %{ rel.groupid, "package_id" => rel.packageid, "release_id" => rel.releaseid, "file_id" => rel.fileid, "step3" => "Delete File", "im_sure" => '1', "submit" => "Delete File " } http_transaction( page, method, form ) end # Add file to release. def add_file( userfile ) page = '/frs/admin/editrelease.php' method = "post_content" type_id = rel.type || userfile[%r|\.[^\./]+$|] type_id = FILETYPES[type_id] proc_id = PROCESSORS[rel.processor] userfile = open( userfile ) form = { "group_id" => rel.groupid, "package_id" => rel.packageid, "release_id" => rel.releaseid, "step2" => '1', "userfile" => userfile, "type_id" => type_id, "processor_id" => proc_id, "submit" => "Add This File" } http_transaction( page, method, form ) #, extheader ) end # http transaction def http_transaction( page, method, form, extheader={} ) client = HTTPAccess2::Client::new ENV['HTTP_PROXY'] client.debug_dev = STDERR if ENV['DEBUG'] client.set_cookie_store( rel.cookie_jar ) # fixes http-access2 bug client.redirect_uri_callback = lambda do |res| page = res.header['location'].first page = page =~ %r/http/ ? page : "http://#{ rel.host }/#{ page }" page end page.sub!(/^\//, '') uri = "http://#{ rel.host }/#{ page }" response = client.send method, uri, form, extheader client.save_cookie_store return response end end # fixes http-access2 bug BEGIN { require "reap/vendor/http-access2" module WebAgent::CookieUtils def domain_match(host, domain) case domain when /\d+\.\d+\.\d+\.\d+/ return (host == domain) when '.' return true when /^\./ #return tail_match?(domain, host) return tail_match?(host, domain) else return (host == domain) end end end }