gem-dependent 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +6 -0
- data/Gemfile.lock +34 -0
- data/Rakefile +20 -0
- data/Readme.md +42 -0
- data/VERSION +1 -0
- data/gem-dependent.gemspec +46 -0
- data/lib/rubygems/commands/dependent_command.rb +46 -0
- data/lib/rubygems/dependent.rb +89 -0
- data/lib/rubygems_plugin.rb +3 -0
- data/spec/dependent_spec.rb +56 -0
- data/spec/fixtures/gemcutter_specs.yml +9008 -0
- metadata +77 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.1.2)
|
5
|
+
gemcutter (0.6.1)
|
6
|
+
git (1.2.5)
|
7
|
+
jeweler (1.4.0)
|
8
|
+
gemcutter (>= 0.1.0)
|
9
|
+
git (>= 1.2.5)
|
10
|
+
rubyforge (>= 2.0.0)
|
11
|
+
json_pure (1.4.6)
|
12
|
+
parallel (0.5.0)
|
13
|
+
rake (0.8.7)
|
14
|
+
rspec (2.0.1)
|
15
|
+
rspec-core (~> 2.0.1)
|
16
|
+
rspec-expectations (~> 2.0.1)
|
17
|
+
rspec-mocks (~> 2.0.1)
|
18
|
+
rspec-core (2.0.1)
|
19
|
+
rspec-expectations (2.0.1)
|
20
|
+
diff-lcs (>= 1.1.2)
|
21
|
+
rspec-mocks (2.0.1)
|
22
|
+
rspec-core (~> 2.0.1)
|
23
|
+
rspec-expectations (~> 2.0.1)
|
24
|
+
rubyforge (2.0.4)
|
25
|
+
json_pure (>= 1.1.7)
|
26
|
+
|
27
|
+
PLATFORMS
|
28
|
+
ruby
|
29
|
+
|
30
|
+
DEPENDENCIES
|
31
|
+
jeweler
|
32
|
+
parallel
|
33
|
+
rake
|
34
|
+
rspec (~> 2)
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
task :default => :spec
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
4
|
+
t.rspec_opts = '--backtrace --color'
|
5
|
+
end
|
6
|
+
|
7
|
+
begin
|
8
|
+
require 'jeweler'
|
9
|
+
Jeweler::Tasks.new do |gem|
|
10
|
+
gem.name = 'gem-dependent'
|
11
|
+
gem.summary = "See which gems depend on your gems"
|
12
|
+
gem.email = "grosser.michael@gmail.com"
|
13
|
+
gem.homepage = "http://github.com/grosser/#{gem.name}"
|
14
|
+
gem.authors = ["Michael Grosser"]
|
15
|
+
end
|
16
|
+
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler, or one of its dependencies, is not available. Install it with: gem install jeweler"
|
20
|
+
end
|
data/Readme.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
Install
|
2
|
+
=======
|
3
|
+
sudo gem install gem-dependent
|
4
|
+
|
5
|
+
Usage
|
6
|
+
=====
|
7
|
+
gem dependent my_gem
|
8
|
+
|
9
|
+
--source URL Query this source (e.g. http://rubygems.org)
|
10
|
+
--no-progress Do not show progress
|
11
|
+
--fetch-limit N Fetch specs for max N gems (for fast debugging)
|
12
|
+
|
13
|
+
Output
|
14
|
+
======
|
15
|
+
|
16
|
+
$ gem dependent my_gem --source http://rubygems.org
|
17
|
+
other_gem >= 1.2.1
|
18
|
+
even_more = 0.0.1
|
19
|
+
|
20
|
+
$ gem dependent XXX --source http://rubygems.org --no-progress | wc -l
|
21
|
+
|
22
|
+
# Fun-facts from 2010-11-03
|
23
|
+
bundler: 263
|
24
|
+
activesupport: 983
|
25
|
+
activerecord: 566
|
26
|
+
|
27
|
+
hoe: 1454
|
28
|
+
jeweler: 234
|
29
|
+
echoe: 85
|
30
|
+
|
31
|
+
nokogiri: 516
|
32
|
+
hpricot: 297
|
33
|
+
|
34
|
+
TODO
|
35
|
+
=====
|
36
|
+
- include reverse dependencies (a > b > c --> a = [b,c])
|
37
|
+
|
38
|
+
Author
|
39
|
+
======
|
40
|
+
[Michael Grosser](http://grosser.it)
|
41
|
+
grosser.michael@gmail.com
|
42
|
+
Hereby placed under public domain, do what you want, just do not hold me accountable...
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{gem-dependent}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Michael Grosser"]
|
12
|
+
s.date = %q{2010-11-03}
|
13
|
+
s.email = %q{grosser.michael@gmail.com}
|
14
|
+
s.files = [
|
15
|
+
"Gemfile",
|
16
|
+
"Gemfile.lock",
|
17
|
+
"Rakefile",
|
18
|
+
"Readme.md",
|
19
|
+
"VERSION",
|
20
|
+
"gem-dependent.gemspec",
|
21
|
+
"lib/rubygems/commands/dependent_command.rb",
|
22
|
+
"lib/rubygems/dependent.rb",
|
23
|
+
"lib/rubygems_plugin.rb",
|
24
|
+
"spec/dependent_spec.rb",
|
25
|
+
"spec/fixtures/gemcutter_specs.yml"
|
26
|
+
]
|
27
|
+
s.homepage = %q{http://github.com/grosser/gem-dependent}
|
28
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
29
|
+
s.require_paths = ["lib"]
|
30
|
+
s.rubygems_version = %q{1.3.7}
|
31
|
+
s.summary = %q{See which gems depend on your gems}
|
32
|
+
s.test_files = [
|
33
|
+
"spec/dependent_spec.rb"
|
34
|
+
]
|
35
|
+
|
36
|
+
if s.respond_to? :specification_version then
|
37
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
38
|
+
s.specification_version = 3
|
39
|
+
|
40
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
41
|
+
else
|
42
|
+
end
|
43
|
+
else
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rubygems/command'
|
2
|
+
require 'rubygems/dependent'
|
3
|
+
|
4
|
+
class Gem::Commands::DependentCommand < Gem::Command
|
5
|
+
def initialize
|
6
|
+
super 'dependent', 'Show which gems depend on a gem', :progress => true
|
7
|
+
|
8
|
+
add_option('--source URL', 'Query these sources (e.g. http://gemcutter.org)') do |remote, _|
|
9
|
+
options[:source] = remote.to_s.split(',')
|
10
|
+
end
|
11
|
+
|
12
|
+
add_option('--no-progress', 'Do not show progress') do
|
13
|
+
options[:progress] = false
|
14
|
+
end
|
15
|
+
|
16
|
+
add_option('--fetch-limit N', Integer, 'Fetch specs for max N gems (for fast debugging)') do |limit, _|
|
17
|
+
options[:fetch_limit] = limit
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def arguments
|
22
|
+
"GEMNAME which gems depend on a gem"
|
23
|
+
end
|
24
|
+
|
25
|
+
def usage
|
26
|
+
"#{program_name} GEMNAME"
|
27
|
+
end
|
28
|
+
|
29
|
+
def execute
|
30
|
+
gem = get_all_gem_names.first
|
31
|
+
gems_and_dependencies = Gem::Dependent.find(gem, options)
|
32
|
+
gems_and_dependencies.each do |gem, dependencies|
|
33
|
+
requirements = dependencies.map do |dependency|
|
34
|
+
formatted_dependency(dependency)
|
35
|
+
end.join(', ')
|
36
|
+
puts "#{gem} #{requirements}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def formatted_dependency(dependency)
|
43
|
+
type = " (#{dependency.type})" if dependency.type == :development
|
44
|
+
"#{dependency.requirement}#{type}"
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'parallel'
|
2
|
+
require 'rubygems/spec_fetcher'
|
3
|
+
|
4
|
+
module Gem
|
5
|
+
class Dependent
|
6
|
+
VERSION = File.read( File.join(File.dirname(__FILE__),'..','..','VERSION') ).strip
|
7
|
+
|
8
|
+
def self.find(gem, options={})
|
9
|
+
specs_and_sources = with_changed_source(options[:source]) do
|
10
|
+
all_specs_and_sources
|
11
|
+
end
|
12
|
+
|
13
|
+
if options[:fetch_limit]
|
14
|
+
specs_and_sources = specs_and_sources.first(options[:fetch_limit])
|
15
|
+
end
|
16
|
+
|
17
|
+
puts "Downloading specs for #{specs_and_sources.size} gems" if options[:progress]
|
18
|
+
|
19
|
+
# fetch dependencies
|
20
|
+
gem_names_and_dependencies = Parallel.map(specs_and_sources, :in_processes => 20) do |spec_tuple, source_uri|
|
21
|
+
print '.' if options[:progress]
|
22
|
+
name = spec_tuple.first
|
23
|
+
dependencies = dependencies(spec_tuple, source_uri)
|
24
|
+
[name, dependencies]
|
25
|
+
end
|
26
|
+
|
27
|
+
print "\n" if options[:progress]
|
28
|
+
|
29
|
+
# select those that depend on #{gem}
|
30
|
+
gem_names_and_dependencies.map do |_, dependencies|
|
31
|
+
found = dependencies.select{|d| d.name == gem}
|
32
|
+
next if found.empty?
|
33
|
+
[_, found]
|
34
|
+
end.compact
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# dependencies for given gem
|
40
|
+
def self.dependencies(spec_tuple, source_uri)
|
41
|
+
begin
|
42
|
+
fetcher = Gem::SpecFetcher.fetcher
|
43
|
+
fetcher.fetch_spec(spec_tuple, URI.parse(source_uri)).dependencies
|
44
|
+
rescue Gem::RemoteFetcher::FetchError, Zlib::DataError => e
|
45
|
+
$stderr.puts e
|
46
|
+
[]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.all_specs_and_sources
|
51
|
+
fetcher = Gem::SpecFetcher.fetcher
|
52
|
+
all = true
|
53
|
+
matching_platform = false
|
54
|
+
prerelease = false
|
55
|
+
name = Gem::Dependency.new(//i, Gem::Requirement.default)
|
56
|
+
specs_and_sources = fetcher.find_matching name, all, matching_platform, prerelease
|
57
|
+
uniq_by(specs_and_sources){|a|a.first.first}
|
58
|
+
end
|
59
|
+
|
60
|
+
# get unique elements from an array (last found is used)
|
61
|
+
# http://drawohara.com/post/146659159/ruby-enumerable-uniq-by
|
62
|
+
def self.uniq_by(array, &block)
|
63
|
+
uniq = {}
|
64
|
+
array.each_with_index do |val, idx|
|
65
|
+
key = block.call(val)
|
66
|
+
uniq[key] = [idx, val]
|
67
|
+
end
|
68
|
+
values = uniq.values
|
69
|
+
values.sort!{|a,b| a.first <=> b.first}
|
70
|
+
values.map!{|pair| pair.last}
|
71
|
+
values
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.with_changed_source(sources)
|
75
|
+
sources = [*sources].compact
|
76
|
+
if sources.empty?
|
77
|
+
yield
|
78
|
+
else
|
79
|
+
begin
|
80
|
+
old = Gem.sources
|
81
|
+
Gem.sources = sources
|
82
|
+
yield
|
83
|
+
ensure
|
84
|
+
Gem.sources = old
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../lib', File.dirname(__FILE__))
|
2
|
+
require 'lib/rubygems/dependent' # normal require does not work once gem is installed, wtf...
|
3
|
+
|
4
|
+
describe Gem::Dependent do
|
5
|
+
before do
|
6
|
+
Gem::SpecFetcher.fetcher = nil # reset cache
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:fixture){ YAML.load(File.read('spec/fixtures/gemcutter_specs.yml')) }
|
10
|
+
let(:hoe_gems){
|
11
|
+
[
|
12
|
+
["7digital", ["hoe"]],
|
13
|
+
["abingo_port", ["hoe"]],
|
14
|
+
["abundance", ["hoe"]],
|
15
|
+
["actionview-data", ["hoe"]],
|
16
|
+
["active_link_to", ["hoe"]],
|
17
|
+
["activemerchant-paymentech-orbital", ["hoe"]],
|
18
|
+
["active_nomad", ["hoe"]],
|
19
|
+
["active_presenter", ["hoe"]],
|
20
|
+
["activerecord-fast-import", ["hoe"]],
|
21
|
+
["activerecord-jdbc-adapter", ["hoe"]]
|
22
|
+
]
|
23
|
+
}
|
24
|
+
|
25
|
+
def simplify(dependencies)
|
26
|
+
dependencies.map{|name, deps| [name, deps.map{|d| d.name}] }
|
27
|
+
end
|
28
|
+
|
29
|
+
def stub_source(gem_source = nil)
|
30
|
+
gem_source ||= 'http://gemcutter.org'
|
31
|
+
Gem::SpecFetcher.fetcher.should_receive(:load_specs).with(URI.parse(gem_source), 'specs').and_return(fixture)
|
32
|
+
Gem.sources = [gem_source]
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'finds dependencies for given gem' do
|
36
|
+
stub_source
|
37
|
+
dependencies = simplify(Gem::Dependent.find('hoe'))
|
38
|
+
dependencies.should == hoe_gems
|
39
|
+
end
|
40
|
+
|
41
|
+
it "obeys fetch-limit" do
|
42
|
+
stub_source
|
43
|
+
dependencies = simplify(Gem::Dependent.find('hoe', :fetch_limit => 100))
|
44
|
+
dependencies.should == hoe_gems.first(4)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "can use given source" do
|
48
|
+
source = 'http://rubygems.org'
|
49
|
+
stub_source(source)
|
50
|
+
Gem::Dependent.find('hoe', :source => source)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "has a VERSION" do
|
54
|
+
Gem::Dependent::VERSION.should =~ /^\d+\.\d+\.\d+$/
|
55
|
+
end
|
56
|
+
end
|