nixpkgs/pkgs/development/interpreters/ruby/gem_nix_command.patch
Marc Weber 92662d3d0f fix sup & enhance ruby import
sup,gem:
  * no longer requires /homeless-shelter to be built
  * sup, gem can be run immediately without exporting GEM_HOME

ruby-support:
  * using mirror server of rubyforge
  * [..] is added at the end of long truncated long descriptions

svn path=/nixpkgs/trunk/; revision=16408
2009-07-16 20:00:02 +00:00

245 lines
6.9 KiB
Diff

diff --git a/lib/rubygems/command_manager.rb b/lib/rubygems/command_manager.rb
index 0a19016..ef66d30 100644
--- a/lib/rubygems/command_manager.rb
+++ b/lib/rubygems/command_manager.rb
@@ -70,6 +70,7 @@ class Gem::CommandManager
register_command :unpack
register_command :update
register_command :which
+ register_command :nix
end
##
diff --git a/lib/rubygems/commands/nix_command.rb b/lib/rubygems/commands/nix_command.rb
new file mode 100644
index 0000000..005d5a9
--- /dev/null
+++ b/lib/rubygems/commands/nix_command.rb
@@ -0,0 +1,226 @@
+require 'net/http'
+require 'rubygems/command'
+require 'rubygems/doc_manager'
+require 'rubygems/install_update_options'
+require 'rubygems/dependency_installer'
+require 'rubygems/local_remote_options'
+require 'rubygems/validator'
+require 'rubygems/exceptions'
+require 'rubygems/version_option'
+require 'rubygems/version'
+require 'open3'
+
+
+def nixname(gem)
+ s = "#{gem}" == gem ? gem : gem.full_name
+ s.gsub(/[.-]/,'_')
+end
+
+def nixdescription(spec)
+ desc_from_spec = spec.description
+ desc = desc_from_spec.sub(/[.].*/,'') # only keep first sentence
+ desc = desc.length > 120 \
+ ? "description = \"#{ desc[0..120] }\"; # cut to 120 chars" \
+ : "description = \"#{ desc }\";"
+ desc = desc.sub(/";$/,"[...]\";") if desc != desc_from_spec
+ desc.gsub("\n"," ") # no \ns in description
+end
+
+##
+# tool creating nix expression to install gems (from ruby forge etc)
+#
+# this is work in progress
+
+class Gem::Commands::NixCommand < Gem::Command
+
+ include Gem::VersionOption
+ include Gem::LocalRemoteOptions
+ include Gem::InstallUpdateOptions
+
+ def initialize
+ defaults = Gem::DependencyInstaller::DEFAULT_OPTIONS.merge({
+ })
+ super 'nix', 'create a nix file containing expressions of the gems', defaults
+ end
+
+ def description # :nodoc:
+ <<-EOF
+ create a nix file containing expressions of the gems
+ There are many gems. So it's best to only specify some target gems and
+ take them into acocunt with their deps
+ TODO more details
+ EOF
+ end
+
+ def usage # :nodoc:
+ "#{program_name} GEMNAME [GEMNAME ...] [options] -- --build-flags"
+ end
+
+ def arguments # :nodoc:
+ "GEMNAME name of gem to be added to the expressions file"
+ end
+
+ def defaults_str # :nodoc:
+ # what to put in here ? TODO (probably nothing is ok)
+ ""
+ end
+
+ def execute
+
+ begin
+ @prerelease = false;
+
+ args = options[:args];
+
+ @gems_with_deps = {}
+ @seen = {}
+
+ # args to dep informations
+ args.map { |arg|
+ if arg =~ /(.+)-?(.*)?/ then
+ gem_name = $1
+ version = $2.empty? ? Gem::Requirement.default : Gem::Version.new($2)
+ else
+ raise Gem::CommandLineError, "could'nt parse arg. expected: name or name-version"
+ end
+
+ print "adding gem_name\n"
+
+ adddep(Gem::Dependency.new gem_name, version)
+ }
+
+ print " total: #{@gems_with_deps.length}\n"
+
+
+ out = "
+ # WARNING: automatically generated CODE
+ # This section has been generated by gem nix #{args.join(" ")}
+ # the gem nix command has been added by a nix patch to ruby gems
+ "
+ # define aliases
+ aliases = {}
+ @gems_with_deps.each{ |key, (spec, src, deps)|
+ aliases[spec.name] = spec \
+ if aliases[spec.name].nil? || aliases[spec.name].version < spec.version
+
+ src_url = "http://gems.rubyforge.org/gems/#{spec.full_name}.gem"
+
+ # [> get true mirror url reading redirect contents
+ # h = Net::HTTP.new('gems.rubyforge.org', 80)
+ # resp, data = h.get("/gems/#{spec.full_name}.gem", nil)
+ # if resp.code == "200" then
+ # src_url = "http://gems.rubyforge.org/gems/#{spec.full_name}.gem"
+ # else if resp.code == "302" then
+ # src_url = resp['location']
+ # print "redirection: http://gems.rubyforge.org/gems/#{spec.full_name}.gem -> #{src_url}\n"
+ # else
+ # raise Gem::DependencyError.new("unkown http return code #{resp} #{data}")
+ # end
+ # end
+
+ #raise Gem::DependencyError("src_url is nil, 302 redirection failed?") if src_url.nil?
+
+ out = "
+ #{out}
+ #{nixname spec} = rubyDerivation {
+ name = \"ruby-#{spec.full_name}\"; # full_name
+ nameNoVersion = \"#{nixname spec.name}\";
+ propagatedBuildInputs = [ #{deps.map {|n| n.nil? ? "" : (nixname n) }.join(" ")} ];
+ src = fetchurl {
+ url = \"#{src_url}\";
+ sha256 = \"#{nixhashof src_url}\";
+ };
+ meta = {
+ homepage = \"#{spec.homepage}\";
+ license = [#{spec.licenses.map{|l| "\"#{l}\""}.join(" ") }]; # one of ?
+ #{nixdescription spec}
+ longDescription = \"#{ spec.description }\";
+ };
+ };\n"
+ }
+
+ out = "#{out}\n# aliases\n"
+ aliases.each { |key, spec |
+ out = "#{out}#{nixname key}=#{nixname spec};\n"
+ }
+
+ print out
+ exit_code = 0
+
+ rescue => e
+ puts e.inspect
+ puts e.backtrace
+ end
+
+
+ end
+
+ # helper funtions ================
+
+ def adddep(dep)
+ gem = find_gem_with_source(dep)
+ raise Gem::CommandLineError, "couldn't find #{dep}" if gem.nil?
+ full_name = gem[0].full_name
+
+ return if @seen[full_name]
+ @seen[full_name] = true # there maybe circular dependencies. thus mark this gem seen as early as possible
+
+ # distinguish runtime / buildtime deps? (TODO)
+ deps = gem[0].dependencies
+
+ print " total deps of #{full_name}: #{deps.length}\n"
+
+ dep_specs = []
+ # recurse while collecting deps
+ deps.each {|dep_var| dep_specs.push(adddep(dep_var)) }
+
+
+ @gems_with_deps[full_name] = [
+ gem[0], # spec
+ gem[1], # src
+ dep_specs # deps
+ ]
+ gem[0] # only return spec, no source for dep list
+ end
+
+
+ # copied from dependency_installer, stripped
+ def find_gem_with_source(dep)
+ gems_and_sources = []
+
+ # no local
+
+ requirements = dep.version_requirements.requirements.map do |req, ver|
+ req
+ end
+
+ all = true
+ found = Gem::SpecFetcher.fetcher.fetch dep, all, true, @prerelease
+ found.reverse[0]
+ end
+
+
+ def nixhashof(src)
+ cashfile="#{ENV['HOME']}/.nix-ruby-gems-cache"
+ cash = {}
+ if FileTest.exists?(cashfile)
+ File.open(cashfile,'r') do |f| Marshal.load(f) end
+ end
+
+ if cash[src].nil? then
+ tmp="/tmp/ruby-gems-nix-tmp-file"
+ raise Gem::DependencyError("could'nt nix-prefetch #{src}") \
+ if (not system("nix-prefetch-url #{src.gsub(/([:= `$;])/,'\\\\\1')} > #{tmp} 2>/dev/null")) || $? != 0
+ file = File.new(tmp)
+ hash = file.readlines().first().split("\n")[0] # remove trailing \n
+ file.close()
+ File.delete(tmp)
+ cash[src] = hash
+
+ File.open(cashfile, "w+") do |f| Marshal.dump(cash, f) end
+ end
+
+ return cash[src]
+ end
+
+end