2009-06-30 15:29:20 +01:00
|
|
|
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
|
2009-07-16 21:00:02 +01:00
|
|
|
index 0000000..005d5a9
|
2009-06-30 15:29:20 +01:00
|
|
|
--- /dev/null
|
|
|
|
+++ b/lib/rubygems/commands/nix_command.rb
|
2009-07-16 21:00:02 +01:00
|
|
|
@@ -0,0 +1,226 @@
|
2009-06-30 15:29:20 +01:00
|
|
|
+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)
|
2009-07-16 21:00:02 +01:00
|
|
|
+ s = "#{gem}" == gem ? gem : gem.full_name
|
2009-06-30 15:29:20 +01:00
|
|
|
+ s.gsub(/[.-]/,'_')
|
|
|
|
+end
|
|
|
|
+
|
2009-07-16 21:00:02 +01:00
|
|
|
+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
|
|
|
|
+
|
2009-06-30 15:29:20 +01:00
|
|
|
+##
|
|
|
|
+# 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
|
|
|
|
+
|
2009-07-16 21:00:02 +01:00
|
|
|
+ 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?
|
2009-06-30 15:29:20 +01:00
|
|
|
+
|
|
|
|
+ out = "
|
|
|
|
+ #{out}
|
|
|
|
+ #{nixname spec} = rubyDerivation {
|
2009-06-30 22:45:17 +01:00
|
|
|
+ name = \"ruby-#{spec.full_name}\"; # full_name
|
2009-07-16 21:00:02 +01:00
|
|
|
+ nameNoVersion = \"#{nixname spec.name}\";
|
2009-06-30 15:29:20 +01:00
|
|
|
+ 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 ?
|
2009-07-16 21:00:02 +01:00
|
|
|
+ #{nixdescription spec}
|
2009-06-30 15:29:20 +01:00
|
|
|
+ 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
|