#!/opt/local/bin/ruby

# File: gems_to_portfile.rb
# Written by: Paul Guyot (pguyot@kallisys.net)
# History:
# Version: 1.2 (2007/04/08)
# - Updated to new gems internal APIs.
# - Console UI (Silent UI no longer asks for versions)
# Version: 1.1 (2006/11/08)
# - Silent UI (avoids breaks)
# - Handle empty long description.
# - Download files to /tmp/ and clean them afterwards (yay!)
# - Don't download the file if it already exists in /tmp/ (like if an error
# occurred)
# - Downcase the name for the directory.
# Version: 1.0 (2006/11/06)

require "rubygems"
require "rubygems/format"
require "rubygems/remote_installer"
require "digest/sha1"
require "digest/md5"

class Portfile
	def initialize gem_file
		format = Gem::Format.from_file_by_path gem_file
		@spec = format.spec
		@name = @spec.name.downcase
		@version = @spec.version.to_s
		# Escape brackets, as Tcl interpret them.
		@description = @spec.summary.gsub(/\[/, '\\[').gsub(/\]/, '\\]')
		long_description = @spec.description || @description
		@long_description = long_description.
			gsub(/\[/, '\\[').gsub(/\]/, '\\]')
		data = IO.read gem_file
		@checksum_sha1 = Digest::SHA1.hexdigest data
		@checksum_md5 = Digest::MD5.hexdigest data
		@checksum_rmd160 = `openssl rmd160 #{gem_file}`.gsub!(/.*= /, "").chop!
		@homepage = @spec.homepage
	end
	
	def to_s
		output = "# $Id$\n"
		output += "\n"
		output += "PortSystem			1.0\n"
		output += "PortGroup			ruby 1.0\n"
		output += "ruby.setup			#{@spec.name} #{@version} gem {} rubyforge_gem\n"
		output += "maintainers			nomaintainer@macports.org\n"
		output += "description			"
		output += break_lines(@description, 57, "					")
		output += "long_description	"
		output += break_lines(@long_description, 57, "					")
		output += "checksums			md5 #{@checksum_md5} \\\n"
		output += "					sha1 #{@checksum_sha1} \\\n"
		output += "					rmd160 #{@checksum_rmd160}\n"
		output += "homepage			#{@homepage}\n" if @homepage
		output += "\n"
		# put dependencies now.
		dependencies = @spec.dependencies
		output += "depends_lib-append" unless dependencies.empty?
		@spec.dependencies.each do |dep_gem|
			output += " \\\n					port:rb-#{dep_gem.name.downcase}"
		end
		output += "\n" unless dependencies.empty?
		output
	end
	
	def name
		"rb-#{@name}"
	end
	
private
	# Break a text into separate lines.
	# Typically used for descriptions.
	def break_lines(text, maxwidth, padding)
		if text.size <= maxwidth then
			text + "\n"
		else
			# break text in words, up to maxwidth - 1.
			space_index = text.rindex(' ', maxwidth - 1) || maxwidth - 1
			this_line = text[0..space_index] + "\\\n"
			remaining = text[space_index + 1..-1]
			this_line + padding + break_lines(remaining, maxwidth, padding)
		end
	end
end

class GemsToPortfile
	def self.main args
		Gem::DefaultUserInteraction.ui = Gem::ConsoleUI.new
		case args.size
		when 0
			puts "Gems to Portfile translation script"
			syntax
		when 1
			self.new args[0]
		else
			puts "Syntax error"
			syntax
		end
	end
	
	def self.syntax
		puts "Syntax: #{$0} (path_to_file.gem|gem_name)"
	end
	
	def initialize arg
		# if the file exists, consider the argument was a file.
		clean_file = true
		if File.exists? arg
			file_path = arg
			clean_file = false
		else
			# otherwise, consider it was the name of a gem.
			remote_installer = Gem::RemoteInstaller.new
			spec, source = remote_installer.find_gem_to_install(arg, ANY_VERSION)
			file_path = "/tmp/#{spec.full_name}.gem"
			remote_installer.download_gem(
				file_path, source, spec) unless File.exists? file_path
		end
		
		portfile = Portfile.new file_path
		port_name = portfile.name
		FileUtils.mkdir_p port_name
		portfile_file = File.new("#{port_name}/Portfile", "w")
		portfile_file << portfile
		portfile_file.close
	end
	
	ANY_VERSION = Gem::Version::Requirement.new "> 0.0.0"
end


GemsToPortfile.main $*
