How to install ruby gem packages without Internet?

git_stats is a good tool to analyze the statistics of a git repo, there is an issue tomgi/git_stats#45 How to Install Offline in that project, I think this is a good question, sometimes the speed or quality of Internet is not so fast and stable, or we want to install a gem package on a server that can only access internal network only, so I tried to figure it out, that’s the solution:

Milly/gem-fetch-dependencies is a ruby script posted on gist, it can help us fetch gem packages with the dependency, we can’t just fetch the package we want to use via gem fetch , because it doesn’t handle the dependency issue, that’s why we need this script, download the script(raw) first:

https://gist.github.com/Milly/909564/raw/c3c921e78b6736197558ee44efb84a495f4c1505/gem-fetch-dependencies
[ruby]#!/usr/bin/ruby

require ‘rubygems’
require ‘rubygems/commands/fetch_command’

class Gem::Commands::FetchCommand
def add_version_option_with_fetch_depends
add_version_option_without_fetch_depends
add_option(‘-y’, ‘–[no-]dependencies’,
"Fetch dependent gems") do |value, options|
options[:dependencies] = value
end
end

def get_all_gem_names_with_fetch_depends
@dependent_gem_names || get_all_gem_names_without_fetch_depends
end

def execute_with_fetch_depends
execute_without_fetch_depends
if options[:dependencies] then
@dependent_gem_names = get_dependent_gem_names
options[:version] = nil
execute_without_fetch_depends
end
end

[:add_version_option, :get_all_gem_names, :execute].each do |target|
feature = "fetch_depends"
alias_method "#{target}_without_#{feature}", target
alias_method target, "#{target}_with_#{feature}"
end

private
def get_dependent_gem_names
version = options[:version] || Gem::Requirement.default
request_gem_names = get_all_gem_names_without_fetch_depends.uniq
to_do = fetch_specs_by_names_and_version(request_gem_names, version)
seen = {}

until to_do.empty? do
spec = to_do.shift
next if spec.nil? or seen[spec.name]
seen[spec.name] = true
deps = spec.runtime_dependencies
deps.each do |dep|
requirements = dep.requirement.requirements.map { |req,| req }
all = !dep.prerelease? and
(requirements.length > 1 or
(requirements.first != ">=" and requirements.first != ">"))
result = fetch_spec(dep, all)
to_do.push(result)
end
end

gem_names = seen.map { |name,| name }
gem_names.reject { |name| request_gem_names.include? name }
end

def fetch_specs_by_names_and_version(gem_names, version)
all = Gem::Requirement.default != version
specs = gem_names.map do |gem_name|
dep = Gem::Dependency.new(gem_name, version)
dep.prerelease = options[:prerelease]
fetch_spec(dep, all)
end
specs.compact
end

def fetch_spec(dep, all)
specs_and_sources, errors =
Gem::SpecFetcher.fetcher.fetch_with_errors(dep, all, true,
dep.prerelease?)
if platform = Gem.platforms.last then
filtered = specs_and_sources.select { |s,| s.platform == platform }
specs_and_sources = filtered unless filtered.empty?
end
spec, source_uri = specs_and_sources.sort_by { |s,| s.version }.last
spec
end
end

load `which gem`.rstrip
[/ruby]

and we can easily fetch the gem packages with dependencies with this script like this:
$ ruby gem-fetch-dependencies fetch --dependencies

Once we fetched all the packages, you copy them to everywhere you want, and install them locally:
$ gem install -f --local *.gem

How to find reverse dependency on Debian/Ubuntu based GNU/Linux?

List all the reverse depends of certain package:

$ apt-cache rdepends pkg_name

For example:

$ apt-cache rdepends vde2

And you’ll get result like this:

vde2
Reverse Depends:
virtualbox
qemu-system-x86
qemu-system-sparc
qemu-system-ppc
qemu-system-misc
qemu-system-mips
qemu-system-arm
user-mode-linux
virtualbricks
virtualbox
vdetelweb
libvde-dev
libvde-dev
user-mode-linux
qemu-kvm
qemu-system
liblwipv6-2

More details via $ apt-cache showpkg pkg_name

Package: vde2
Versions:
2.3.2-4 (/var/lib/apt/lists/opensource.nchc.org.tw_debian_dists_wheezy_main_binary-amd64_Packages) (/var/lib/dpkg/status)
Description Language:
File: /var/lib/apt/lists/opensource.nchc.org.tw_debian_dists_wheezy_main_binary-amd64_Packages
MD5: c1d59c710a94c274459c01b82f926c5a
Description Language: en
File: /var/lib/apt/lists/opensource.nchc.org.tw_debian_dists_wheezy_main_i18n_Translation-en
MD5: c1d59c710a94c274459c01b82f926c5a

Reverse Depends:
virtualbox,vde2
qemu-system-x86,vde2
qemu-system-sparc,vde2
qemu-system-ppc,vde2
qemu-system-misc,vde2
qemu-system-mips,vde2
qemu-system-arm,vde2
user-mode-linux,vde2
virtualbricks,vde2
virtualbox,vde2
vdetelweb,vde2
libvde-dev,vde2 2.3.2-1
libvde-dev,vde2 2.3.2-1
user-mode-linux,vde2
qemu-kvm,vde2
qemu-system,vde2
liblwipv6-2,vde2
Dependencies:
2.3.2-4 – adduser (0 (null)) libc6 (2 2.7) libpcap0.8 (2 0.9.8) libvde0 (0 (null)) libvdeplug2 (0 (null)) vde2-cryptcab (0 (null)) qemu-kvm (0 (null)) qemu (0 (null)) vde (0 (null))
Provides:
2.3.2-4 –
Reverse Provides:

If we only want to know the installed dependencies, ask aptitude:

$ aptitude why vde2

It’ll tell us:

i qemu Depends qemu-system (>= 1.1.2+dfsg-6a+deb7u6)
i A qemu-system Recommends vde2

What about recursive depends? Try $ apt-rdepends --reverse pkg_name !
(Install via apt-get install apt-rdepends)

PS: reverse-depends has similar feature, but it’s in ubuntu-dev-tools, which depends on toooooo many packages, so I’ll not suggest you to use it for just finding the dependencies.