From 062363b71c6343f3fec0bced028048a4d2801aa6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Fri, 15 Sep 2006 22:57:05 +0700 Subject: [PATCH] Imported g-gem --- g-gem | 457 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 457 insertions(+) create mode 100755 g-gem diff --git a/g-gem b/g-gem new file mode 100755 index 0000000..a6dc97a --- /dev/null +++ b/g-gem @@ -0,0 +1,457 @@ +#!/usr/bin/env ruby + +require 'rubygems' +require 'rubygems/installer' +require 'rubygems/remote_installer' + +module Gem::Portage + class << self + attr_accessor :configuration + end + + class ConfigFile + attr_accessor :opts + attr_reader :overlay_dirs, :portage_dir, :portage_distdir, :portage_dev_ruby, :category + attr_reader :rubydev_overlay + + def initialize(path="/etc/make.conf") + @path = path + @overlay_dirs = %x(/usr/lib/portage/bin/portageq portdir_overlay).chomp.split(/ +/) + @portage_dir = %x(/usr/lib/portage/bin/portageq portdir).chomp + @portage_distdir = %x(/usr/lib/portage/bin/portageq distdir).chomp + @category = 'dev-ruby' + @ruby_vdb = File.join(%x(/usr/lib/portage/bin/portageq distdir).chomp,@category) + @portage_dir = '/usr/portage' unless File.directory? @portage_dir + @portage_distdir = '/usr/portage/distfiles' unless File.directory? @portage_distdir + @portage_dev_ruby = File.join(@portage_dir,@category) + + @tmp_overlay_dir = "/tmp/ruby-modules_#{Process.pid}" + @overlay_dir = @overlay_dirs.find {|o| File.directory? o} + end + + def setup_overlay(tmp_overlay = false) + @overlay_dir = (tmp_overlay == false && @overlay_dir) || @tmp_overlay_dir + Dir.mkdir(@overlay_dir, 0755) unless File.directory? @overlay_dir + @rubydev_overlay = File.join(@overlay_dir,@category) + Dir.mkdir(@rubydev_overlay, 0755) unless File.directory? @rubydev_overlay + ENV['PORTDIR_OVERLAY'] = @overlay_dir + end + + def cleanup + # Should strictly check to make sure we don't accidentally rm_rf $HOME for example + if @overlay_dir == @tmp_overlay_dir and File.directory? @tmp_overlay_dir and @tmp_overlay_dir =~ /^\/tmp\// + require 'fileutils' + FileUtils.rm_rf @tmp_overlay_dir + end + end + + def env(envvar) + %x(/usr/lib/portage/bin/portageq envvar #{envvar}).chomp + end + + def ebuild_exists(name, gem_version) + portage_dir = File.join(@portage_dev_ruby,name) + overlay_dir = File.join(@rubydev_overlay,name) + version_requirement = gem_version.is_a?(Gem::Version::Requirement) ? gem_version : Gem::Version::Requirement.new(gem_version || ">= 0") + ebuilds = Dir.glob(File.join(portage_dir,'*.ebuild')) + Dir.glob(File.join(overlay_dir,'*.ebuild')) + return false if ebuilds.empty? + ebuilds.map! {|e| File.basename(e).gsub(/\.ebuild$/,'') } + satisfied_ebuild = ebuilds.find do |e| + dep_atom = DependencyAtom.new('='+e) + version = Gem::Version.create(dep_atom.version) + version_requirement.satisfied_by?(version) + end + satisfied_ebuild != nil + end + + end # class ConfigFile + + class Ebuild + + DEFAULT_INSTALL_DIR = ::Gem.dir + + EXTENSION = ".ebuild" + + COMMANDS = %w(help setup clean fetch digest unpack compile test + preinst install postinst qmerge merge unmerge + prerm postrm config package rpm generate) + + class << self + alias_method :for, :new + end + + require 'forwardable' + extend Forwardable + + def_delegators :@spec, :name, :version, :date, :summary, :email, + :homepage, :rubyforge_project, :description, :local?, :remote? + + attr_reader :spec, :file_path + attr_accessor :install_dir, :license + + def initialize(spec) + @spec = spec + end + + def file_path + File.expand_path(File.join(Gem::Portage.configuration.rubydev_overlay, spec.name, "#{spec.full_name}#{EXTENSION}")) + end + + def dirname + File.dirname(file_path) + end + + def basename(include_extension=true) + File.basename(file_path, (EXTENSION unless include_extension) ) + end + + def exists? + File.exists? file_path + end + + def write + require 'fileutils' + dir = File.dirname(file_path) + FileUtils.mkdir_p(dir) unless File.directory?(dir) + File.open(file_path, 'w') { |f| f.write(content) } + end + alias_method :generate, :write + + def local_gentoo_mirror + File.dirname(spec.fetched_from) if spec.local? + end + + def execute(*commands) + raise "Invalid emerge command" unless (commands - COMMANDS).empty? + callcc do |c| + if spec.local? + ENV.with(:GENTOO_MIRRORS => local_gentoo_mirror) do + c.call + end + end + end + generate if commands.delete('generate') + raise "Missing #{file_path}" unless exists? + system("ebuild #{file_path} #{commands.join(' ')}") unless commands.empty? + end + + def digest_file + File.join(dirname, "files", "digest-#{basename(false)}") + end + + def src_uri + uri = spec.fetched_from if spec.respond_to? :fetched_from + if spec.local? + "#{uri}/${P}.gem" + else + "#{uri}/gems/${P}.gem" + end + end + + def gem_src + return spec.fetched_from if spec.local? + "${DISTDIR}/${P}" + end + + def license + "Unknown" + end + + def install_dir + @install_dir || DEFAULT_INSTALL_DIR + end + + def keywords + Gem::Portage.configuration.env('ARCH') + end + + def iuse + "#{'doc' if spec.has_rdoc}" + end + + def enable_test_phase + @test_phase = true + end + + def disable_test_phase + @test_phase = false + end + + def test_phase_enabled? + @test_phase + end + + def gem_command_args + args = [] # %w(--no-portage) + args << "--test" if test_phase_enabled? + args.join(' ') + end + + def depend + category = Gem::Portage.configuration.category + required_ruby = DependencyAtom.from_required_ruby_version(spec) + spec.dependencies.inject(required_ruby) do |s,d| + s + "\n" + DependencyAtom.from_gem_dependency(d, category).to_s + end + end + + def content + require 'date' + doc = <<-EBUILD +# Copyright 1999-#{Date.today.year} Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +inherit ruby gems + +USE_RUBY="ruby18" +DESCRIPTION=#{summary.inspect} +HOMEPAGE=#{homepage.inspect} +SRC_URI=#{src_uri.inspect} + +LICENSE=#{license.inspect} +SLOT="0" +KEYWORDS=#{keywords.inspect} + +IUSE=#{iuse.inspect} +DEPEND=#{depend.inspect.gsub('\n', "\n\t")} + EBUILD + end + end # class Ebuild + + class DependencyAtom + + PREFIX_EXT_RE = /[!~]/ + PREFIX_RE = /(>=|<=|<|>|=)/ + CATEGORY_RE = /\w+-\w+/ + POSTFIX_RE = /\*/ + VERSION_RE = /(\d+(\.\d+)*)+/ + VERSION_EXT_RE = /[a-z]?(_(alpha|beta|pre|rc|p)\d+)?/ + PACKAGE_NAME_RE = /[a-zA-Z0-9_-]+/ + + attr_reader :package_name, :version, :version_ext, + :prefix, :prefix_ext, :postfix, :origin + + def initialize(str) + @origin = str + @prefix_ext, str = $&, $' if /^#{PREFIX_EXT_RE}/ === str + @prefix, str = $&, $' if /^#{PREFIX_RE}/ === str + @category, str = $1, $' if /^(#{CATEGORY_RE})\// === str + @postfix, str = $&, $` if /#{POSTFIX_RE}$/ === str + @version, @version_ext, str = $1, $3, $` if /-#{VERSION_RE}(#{VERSION_EXT_RE})/ === str + raise "Invalid atom: #{@origin}" unless /^#{PACKAGE_NAME_RE}$/ === str + @package_name = $& + end + private :initialize + + alias_method :name, :package_name + attr_accessor :category + + def category + @category or Gem::Portage.configuration.category + end + + ## + # FIXME: support other gentoo atom prefixes + ## + def gem_requirement + return Gem::Version::Requirement.default unless version + full_prefix = "#{prefix_ext}#{prefix}" + gem_prefix = if /^(~>|>|>=|=|!=|<=|<)$/ === full_prefix + full_prefix + elsif not prefix + "=" + end + Gem::Version::Requirement.create(["#{gem_prefix} #{version}"]) + end + + def gem_dependency + Gem::Dependency.new(package_name, [gem_requirement.to_s]) + end + + def to_s + "#{prefix_ext}#{(prefix or "=") if version}#{category+"/" if category}#{package_name}"+ + "#{"-"+version+version_ext if version}#{postfix}" + end + + class << self + def from_s(str) + if str =~ /(.*\/)?(\S+)\.gem$/ # From gem file + atom = from_s($2) + atom.instance_eval { @origin = str } + atom + else + new(str) + end + end + + alias_method :parse, :from_s + + def parse_list(list) + list.map { |str| parse(str) } + end + + def from_gem_dependency(dep, category) + # fixme: + prefix, version = *dep.version_requirements.instance_eval { @requirements.first } + new("#{prefix}#{category}/#{dep.name}-#{version}") + end + + def from_required_ruby_version(spec) + prefix, version = *spec.required_ruby_version.instance_eval { @requirements.first } + "#{prefix}dev-lang/ruby-#{version}" + end + end + end # class DependencyAtom + + class Ebuild + @@gri = nil + @@sources = nil + + def self.navigate(gem_name,gem_version = nil,&block) + if Gem::Portage.configuration.ebuild_exists(gem_name,gem_version) + puts "Ebuild for #{gem_name} exists" if Gem::Portage.configuration.opts[:verbose] + return true + end + # cache source_index_hash, no need to recheck it everytime + @@gri = Gem::RemoteInstaller.new if @@gri.nil? + @@sources = @@gri.source_index_hash if @@sources.nil? + version_requirement = gem_version.is_a?(Gem::Version::Requirement) ? gem_version : Gem::Version::Requirement.new(gem_version || ">= 0") + gem_spec = nil + for source_name,source in @@sources + specs = source.find_name(gem_name, version_requirement) + next if specs.nil? or specs.empty? + # ignore mswin32 platform + satisfied_specs = specs.find_all do |spec| + spec.platform == 'ruby' and + version_requirement.satisfied_by?(spec.version) + end + gem_spec = satisfied_specs[-1] + class << gem_spec + def local?() false; end + def set_source(source) + @source = source + end + def fetched_from + @source + end + end + gem_spec.set_source(source_name) + break + end + if gem_spec.nil? + puts "#{gem_name} not found" + return false + end + yield(gem_spec) + for dep in gem_spec.dependencies + navigate(dep.name, dep.requirement_list, &block) + end + true + end + + def self.create(gem_name,gem_version = nil) + navigate(gem_name, gem_version) do |gem_spec| + puts "Create ebuild for #{gem_spec.full_name}" if Gem::Portage.configuration.opts[:verbose] + gem_ebuild = Gem::Portage::Ebuild.new(gem_spec) + gem_ebuild.write + end + end + + def self.list(gem_name,gem_version = nil) + navigate(gem_name, gem_version) do |gem_spec| + puts "Need ebuild for #{gem_spec.full_name}" if Gem::Portage.configuration.opts[:verbose] + end + end + + def self.get_specs(pkg) + specs = [] + navigate(pkg.package_name,pkg.gem_requirement) { |spec| specs << spec } + specs.reverse + end + end +end # module Gem::Portage + +SHORTMAP = { + 'p' => :prepend, + 'h' => :help, + 'v' => :verbose, +} +LONGMAP = { + 'prepend' => :prepend, + 'verbose' => :verbose, + 'help' => :help, + 'generate' => :generate, +} + +def parse_opts(argv) + opts = { + :prepend => false, + :generate => false, + :help => false, + :verbose => false, + } + packages = [] + + for arg in argv + if arg =~ /^-[^-]/ + for i in 1..arg.length-1 + if SHORTMAP.key? arg[i..i] + opts[SHORTMAP[arg[i..i]]] = true + else + puts "Unknown option '-#{arg[i..i]}'" + end + end + elsif arg =~ /^--/ + if LONGMAP.key? arg[2..-1] + opts[LONGMAP[arg[2..-1]]] = true + else + puts "Unknown option '#{arg}'" + end + else + packages << Gem::Portage::DependencyAtom.new(arg) + end + end + return opts, packages +end + +def main + Gem::Portage.configuration.opts, packages = parse_opts(ARGV) + cfg = Gem::Portage.configuration + cfg.setup_overlay(cfg.opts[:prepend]) + specs = [] + for pkg in packages + specs << Gem::Portage::Ebuild.get_specs(pkg) + end + all_specs = specs.flatten + #if cfg.opts[:prepend] + # for spec in all_specs + # puts spec.full_name + # end + #else + ebuilds = [] + for spec in all_specs + puts "Create ebuild for #{spec.full_name}" if cfg.opts[:verbose] + gem_ebuild = Gem::Portage::Ebuild.new(spec) + gem_ebuild.write + ebuilds << gem_ebuild + end + # No prepend, digest the ebuilds + if cfg.opts[:prepend] == false + ebuilds.each {|ebuild| ebuild.execute('digest')} + end + # don't specify --generate, continue digest and emerge + if cfg.opts[:generate] == false + system('emerge '+ARGV.join(' ')) + else + puts "Ebuilds are in #{cfg.rubydev_overlay}" + end + #end + # don't clean up if --generate because overlay may be /tmp/* + cfg.cleanup unless cfg.opts[:generate] == true +end + +Gem.manage_gems +Gem.configuration = Gem::ConfigFile.new({}) +Gem::Portage.configuration = Gem::Portage::ConfigFile.new +main -- 2.11.4.GIT