[Rubygems-developers] [Patch] temporary buildroot support for gem install

Marcus Rueckert darix at web.de
Wed Jun 28 01:48:57 EDT 2006


hi,

I am one of the maintainer of the Ruby project in the openSUSE Build
Service [1].

One of the goals was of course providing as many ruby libraries as
possible. As gem is getting more and more popular for distributing ruby
libraries, I was looking for a way to provide rpms of gems on the one
hand, but keeping interoperability with gem.

For building rpms i wanted to avoid building as root. That makes it
impossible to use the normal prefixes for the gems. For normal C
programs you have the "make install DESTDIR=%{buildroot}" to provide a
temporary installation root. Python has a
"python setup.py install --root %{buildroot}" for the same purpose.

The attached adds a --build-root parameter to achieve the same.
With a downloaded gem file you can do:
gem install --build-root %{buildroot} /path/to/some.gem

that makes it rather easy to build packages from gems.
In the longterm i will now work on a gem2pkg script. At first only rpm,
but in the longerm support for deb or other binary distros could be
added.

I already build 49 rpms from gem with that patch. :)

Known bugs:
"gem install --build-root $PWD/inst -r somegem" fails with
[[[
ERROR:  While executing gem ... (Errno::EACCES)
Permission denied - /usr/lib/ruby/gems/1.8/cache/sparklines-0.2.7.gem
]]]

Do you consider that bug important?
As my build environments never have network, that use case would never
matter for me. Furthermore this option is only interesting for
packagers, and they always have a local copy of the file.

Thanks for your comments.

    darix

[1] http://en.opensuse.org/Ruby

-- 
           openSUSE - SUSE Linux is my linux
               openSUSE is good for you
                   www.opensuse.org
-------------- next part --------------
Index: lib/rubygems/gem_commands.rb
===================================================================
--- lib/rubygems/gem_commands.rb.orig
+++ lib/rubygems/gem_commands.rb
@@ -59,6 +59,10 @@
       add_option('-i', '--install-dir DIR', '') do |value, options|
         options[:install_dir] = value
       end
+      add_option('-B', '--build-root DIR', 'Temporary installation root. Useful for building packages.') do |value, options|
+        options[:build_root] = File.expand_path(value)
+      end
+
       add_option('-d', '--[no-]rdoc', 'Generate RDoc documentation for the gem on install') do |value, options|
         options[:generate_rdoc] = value
       end
Index: lib/rubygems/installer.rb
===================================================================
--- lib/rubygems/installer.rb.orig
+++ lib/rubygems/installer.rb
@@ -69,7 +69,15 @@
  	  end
  	end
       end
-      
+
+      if @options[:build_root]
+          build_root = @options[:build_root]
+          FileUtils.mkdir_p build_root
+          raise Gem::FilePermissionError.new(build_root) unless File.writable?(build_root)
+          install_dir = build_root + install_dir
+          FileUtils.mkdir_p install_dir
+      end
+
       raise Gem::FilePermissionError.new(install_dir) unless File.writable?(install_dir)
 
       # Build spec dir.
@@ -167,16 +175,25 @@
     # Determines the directory for binaries
     #
     def bindir(install_dir=Gem.dir)
-      if(install_dir == Gem.default_dir)
+      if @options[:build_root]
+          build_root = @options[:build_root]
+          gem_default_dir = File.join(build_root, Gem.default_dir)
+      else
+          gem_default_dir = Gem.default_dir
+          build_root = ""
+      end
+
+      if(install_dir == gem_default_dir)
         # mac framework support
         if defined? RUBY_FRAMEWORK_VERSION
-          File.join(File.dirname(Config::CONFIG["sitedir"]), File.basename(Config::CONFIG["bindir"]))
+          bin_dir = File.join(File.dirname(Config::CONFIG["sitedir"]), File.basename(Config::CONFIG["bindir"]))
         else # generic install
-          Config::CONFIG['bindir']
+          bin_dir = Config::CONFIG['bindir']
         end
       else
-        File.join(install_dir, "bin")
+        bin_dir = File.join(install_dir, "bin")
       end
+      bin_dir = File.join(build_root, bin_dir)
     end
 
     def generate_bin(spec, install_dir=Gem.dir)
-------------- next part --------------
Index: lib/rubygems/gem_commands.rb
===================================================================
--- lib/rubygems/gem_commands.rb.orig
+++ lib/rubygems/gem_commands.rb
@@ -97,6 +97,12 @@
         options[:install_dir] = File.expand_path(value)
       end
 
+      add_option('-B', '--build-root DIR',
+	'Temporary installation root. Useful for building packages.') do 
+	|value, options|
+        options[:build_root] = File.expand_path(value)
+      end
+
       add_option('-d', '--[no-]rdoc', 
 	'Generate RDoc documentation for the gem on install') do
 	|value, options|
Index: lib/rubygems/installer.rb
===================================================================
--- lib/rubygems/installer.rb.orig
+++ lib/rubygems/installer.rb
@@ -74,7 +74,15 @@
  	  end
  	end
       end
-      
+
+      if @options[:build_root]
+          build_root = @options[:build_root]
+          FileUtils.mkdir_p build_root
+          raise Gem::FilePermissionError.new(build_root) unless File.writable?(build_root)
+          install_dir = build_root + install_dir
+          FileUtils.mkdir_p install_dir
+      end
+
       raise Gem::FilePermissionError.new(install_dir) unless File.writable?(install_dir)
 
       # Build spec dir.
@@ -175,16 +183,25 @@
     # Determines the directory for binaries
     #
     def bindir(install_dir=Gem.dir)
-      if(install_dir == Gem.default_dir)
+      if @options[:build_root]
+          build_root = @options[:build_root]
+          gem_default_dir = File.join(build_root, Gem.default_dir)
+      else
+          gem_default_dir = Gem.default_dir
+          build_root = ""
+      end
+
+      if(install_dir == gem_default_dir)
         # mac framework support
         if defined? RUBY_FRAMEWORK_VERSION
-          File.join(File.dirname(Config::CONFIG["sitedir"]), File.basename(Config::CONFIG["bindir"]))
+          bin_dir = File.join(File.dirname(Config::CONFIG["sitedir"]), File.basename(Config::CONFIG["bindir"]))
         else # generic install
-          Config::CONFIG['bindir']
+          bin_dir = Config::CONFIG['bindir']
         end
       else
-        File.join(install_dir, "bin")
+        bin_dir = File.join(install_dir, "bin")
       end
+      bin_dir = File.join(build_root, bin_dir)
     end
 
     def generate_bin(spec, install_dir=Gem.dir)


More information about the Rubygems-developers mailing list