gemirro 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of gemirro might be problematic. Click here for more details.
- checksums.yaml +15 -0
- data/.gitignore +5 -0
- data/.rubocop.yml +24 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/LICENSE +674 -0
- data/MANIFEST +46 -0
- data/README.md +60 -0
- data/Rakefile +10 -0
- data/bin/gemirro +6 -0
- data/gemirro.gemspec +31 -0
- data/lib/gemirro.rb +37 -0
- data/lib/gemirro/cli.rb +63 -0
- data/lib/gemirro/cli/index.rb +24 -0
- data/lib/gemirro/cli/init.rb +17 -0
- data/lib/gemirro/cli/server.rb +19 -0
- data/lib/gemirro/cli/update.rb +18 -0
- data/lib/gemirro/configuration.rb +137 -0
- data/lib/gemirro/gem.rb +70 -0
- data/lib/gemirro/gems_fetcher.rb +126 -0
- data/lib/gemirro/http.rb +37 -0
- data/lib/gemirro/indexer.rb +56 -0
- data/lib/gemirro/mirror_directory.rb +59 -0
- data/lib/gemirro/mirror_file.rb +48 -0
- data/lib/gemirro/server.rb +164 -0
- data/lib/gemirro/source.rb +58 -0
- data/lib/gemirro/version.rb +5 -0
- data/lib/gemirro/versions_fetcher.rb +31 -0
- data/lib/gemirro/versions_file.rb +65 -0
- data/spec/gemirro/cli_spec.rb +51 -0
- data/spec/gemirro/configuration_spec.rb +88 -0
- data/spec/gemirro/gem_spec.rb +37 -0
- data/spec/gemirro/gems_fetcher_spec.rb +104 -0
- data/spec/gemirro/http_spec.rb +36 -0
- data/spec/gemirro/indexer_spec.rb +55 -0
- data/spec/gemirro/mirror_directory_spec.rb +37 -0
- data/spec/gemirro/mirror_file_spec.rb +23 -0
- data/spec/gemirro/server_spec.rb +96 -0
- data/spec/gemirro/source_spec.rb +44 -0
- data/spec/gemirro/versions_fetcher_spec.rb +25 -0
- data/spec/gemirro/versions_file_spec.rb +52 -0
- data/spec/spec_helper.rb +17 -0
- data/task/manifest.rake +9 -0
- data/task/rspec.rake +6 -0
- data/task/rubocop.rake +5 -0
- data/template/config.rb +25 -0
- data/template/public/gems/.gitkeep +0 -0
- metadata +230 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module Gemirro
|
3
|
+
##
|
4
|
+
# The Source class is used for storing information about an external source
|
5
|
+
# such as the name and the Gems to mirror.
|
6
|
+
#
|
7
|
+
# @!attribute [r] name
|
8
|
+
# @return [String]
|
9
|
+
# @!attribute [r] host
|
10
|
+
# @return [String]
|
11
|
+
# @!attribute [r] gems
|
12
|
+
# @return [Array]
|
13
|
+
#
|
14
|
+
class Source
|
15
|
+
attr_reader :name, :host, :gems
|
16
|
+
|
17
|
+
##
|
18
|
+
# @param [String] name
|
19
|
+
# @param [String] host
|
20
|
+
# @param [Array] gems
|
21
|
+
#
|
22
|
+
def initialize(name, host, gems = [])
|
23
|
+
@name = name.downcase.gsub(/\s+/, '_')
|
24
|
+
@host = host.chomp('/')
|
25
|
+
@gems = gems
|
26
|
+
end
|
27
|
+
|
28
|
+
##
|
29
|
+
# Fetches a list of all the available Gems and their versions.
|
30
|
+
#
|
31
|
+
# @return [String]
|
32
|
+
#
|
33
|
+
def fetch_versions
|
34
|
+
Http.get(host + '/' + Configuration.versions_file).body
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# Fetches the `.gem` file of a given Gem and version.
|
39
|
+
#
|
40
|
+
# @param [String] name
|
41
|
+
# @param [String] version
|
42
|
+
# @return [String]
|
43
|
+
#
|
44
|
+
def fetch_gem(name, version)
|
45
|
+
Http.get(host + "/gems/#{name}-#{version}.gem").body
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# Adds a new Gem to the source.
|
50
|
+
#
|
51
|
+
# @param [String] name
|
52
|
+
# @param [String] requirement
|
53
|
+
#
|
54
|
+
def gem(name, requirement = nil)
|
55
|
+
gems << Gem.new(name, requirement)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module Gemirro
|
3
|
+
##
|
4
|
+
# The VersionsFetcher class is used for retrieving the file that contains all
|
5
|
+
# registered Gems and their versions.
|
6
|
+
#
|
7
|
+
# @!attribute [r] source
|
8
|
+
# @return [Source]
|
9
|
+
#
|
10
|
+
class VersionsFetcher
|
11
|
+
attr_reader :source
|
12
|
+
|
13
|
+
##
|
14
|
+
# @param [Source] source
|
15
|
+
#
|
16
|
+
def initialize(source)
|
17
|
+
@source = source
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# @return [Gemirro::VersionsFile]
|
22
|
+
#
|
23
|
+
def fetch
|
24
|
+
Gemirro.configuration.logger.info(
|
25
|
+
"Updating #{source.name} (#{source.host})"
|
26
|
+
)
|
27
|
+
|
28
|
+
VersionsFile.load(source.fetch_versions)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module Gemirro
|
3
|
+
##
|
4
|
+
# The VersionsFile class acts as a small Ruby wrapper around the RubyGems
|
5
|
+
# file that contains all Gems and their associated versions.
|
6
|
+
#
|
7
|
+
# @!attribute [r] versions
|
8
|
+
# @return [Array]
|
9
|
+
# @!attribute [r] versions_hash
|
10
|
+
# @return [Hash]
|
11
|
+
#
|
12
|
+
class VersionsFile
|
13
|
+
attr_reader :versions, :versions_hash
|
14
|
+
|
15
|
+
##
|
16
|
+
# Reads the versions file from the specified String.
|
17
|
+
#
|
18
|
+
# @param [String] content
|
19
|
+
# @return [Gemirro::VersionsFile]
|
20
|
+
#
|
21
|
+
def self.load(content)
|
22
|
+
buffer = StringIO.new(content)
|
23
|
+
reader = Zlib::GzipReader.new(buffer)
|
24
|
+
instance = new(Marshal.load(reader.read))
|
25
|
+
|
26
|
+
reader.close
|
27
|
+
|
28
|
+
instance
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# @param [Array] versions
|
33
|
+
#
|
34
|
+
def initialize(versions)
|
35
|
+
@versions = versions
|
36
|
+
@versions_hash = create_versions_hash
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# Creates a Hash based on the Array containing all versions. This Hash is
|
41
|
+
# used to more easily (and faster) iterate over all the gems/versions.
|
42
|
+
#
|
43
|
+
# @return [Hash]
|
44
|
+
#
|
45
|
+
def create_versions_hash
|
46
|
+
hash = Hash.new { |h, k| h[k] = [] }
|
47
|
+
|
48
|
+
versions.each do |version|
|
49
|
+
hash[version[0]] << version
|
50
|
+
end
|
51
|
+
|
52
|
+
hash
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# Returns an Array containing all the available versions for a Gem.
|
57
|
+
#
|
58
|
+
# @param [String] gem
|
59
|
+
# @return [Array]
|
60
|
+
#
|
61
|
+
def versions_for(gem)
|
62
|
+
versions_hash[gem].map { |version| version[1] }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'gemirro/cli'
|
4
|
+
require 'gemirro/mirror_file'
|
5
|
+
require 'slop'
|
6
|
+
|
7
|
+
# Gemirro tests
|
8
|
+
module Gemirro
|
9
|
+
# CLI tests
|
10
|
+
module CLI
|
11
|
+
describe 'CLI' do
|
12
|
+
include FakeFS::SpecHelpers
|
13
|
+
|
14
|
+
it 'should return options' do
|
15
|
+
options = CLI.options
|
16
|
+
expect(options).to be_a(::Slop)
|
17
|
+
expect(options.config[:strict]).to be_truthy
|
18
|
+
expect(options.config[:banner])
|
19
|
+
.to eq('Usage: gemirro [COMMAND] [OPTIONS]')
|
20
|
+
expect(options.to_s)
|
21
|
+
.to match(/-v, --version(\s+)Shows the current version/)
|
22
|
+
expect(options.to_s)
|
23
|
+
.to match(/-h, --help(\s+)Display this help message./)
|
24
|
+
|
25
|
+
version = options.fetch_option(:v)
|
26
|
+
expect(version.short).to eq('v')
|
27
|
+
expect(version.long).to eq('version')
|
28
|
+
expect(version.call).to be_nil
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should retrieve version information' do
|
32
|
+
expect(CLI.version_information).to eq(
|
33
|
+
"gemirro v#{VERSION} on #{RUBY_DESCRIPTION}"
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should raise SystemExit if file does not exists' do
|
38
|
+
CLI.should_receive(:abort)
|
39
|
+
.with('The configuration file /config.rb does not exist')
|
40
|
+
.and_raise SystemExit
|
41
|
+
expect { CLI.load_configuration('config.rb') }.to raise_error SystemExit
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should raise LoadError if content isn\'t ruby' do
|
45
|
+
file = MirrorFile.new('./config.rb')
|
46
|
+
file.write('test')
|
47
|
+
expect { CLI.load_configuration('config.rb') }.to raise_error LoadError
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'gemirro/mirror_directory'
|
4
|
+
require 'gemirro/configuration'
|
5
|
+
require 'gemirro/source'
|
6
|
+
|
7
|
+
# Configuration tests
|
8
|
+
module Gemirro
|
9
|
+
describe 'Configuration' do
|
10
|
+
include FakeFS::SpecHelpers
|
11
|
+
|
12
|
+
it 'should return configuration' do
|
13
|
+
expect(Gemirro.configuration).to be_a Configuration
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should return logger' do
|
17
|
+
expect(Gemirro.configuration.logger).to be_a Logger
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should return template directory' do
|
21
|
+
FakeFS::FileSystem.clone(
|
22
|
+
File.expand_path(
|
23
|
+
'./',
|
24
|
+
Pathname.new(__FILE__).realpath
|
25
|
+
)
|
26
|
+
)
|
27
|
+
expect(Configuration.template_directory).to eq(
|
28
|
+
File.expand_path(
|
29
|
+
'../../../template',
|
30
|
+
Pathname.new(__FILE__).realpath
|
31
|
+
)
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should return default config file' do
|
36
|
+
expect(Configuration.default_configuration_file).to eq('/config.rb')
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should return marshal identifier' do
|
40
|
+
expect(Configuration.marshal_identifier).to match(/Marshal\.(\d+)\.(\d+)/)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should return versions file' do
|
44
|
+
expect(Configuration.versions_file).to match(/specs\.(\d+)\.(\d+).gz/)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should return marshal file' do
|
48
|
+
expect(Configuration.marshal_version).to eq(
|
49
|
+
"#{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}"
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'Configuration::instance' do
|
55
|
+
before(:each) do
|
56
|
+
@config = Configuration.new
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'return mirror directory' do
|
60
|
+
@config.should_receive(:gems_directory).once.and_return('/tmp')
|
61
|
+
expect(@config.mirror_directory).to be_a(MirrorDirectory)
|
62
|
+
expect(@config.mirror_directory.path).to eq('/tmp')
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should return gems directory' do
|
66
|
+
@config.should_receive(:destination).once.and_return('/tmp')
|
67
|
+
expect(@config.gems_directory).to eq('/tmp/gems')
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should return ignored gems' do
|
71
|
+
expect(@config.ignored_gems).to eq(Hash.new)
|
72
|
+
expect(@config.ignore_gem?('rake', '1.0.0')).to be_falsy
|
73
|
+
expect(@config.ignore_gem('rake', '1.0.0')).to eq(['1.0.0'])
|
74
|
+
expect(@config.ignored_gems).to eq('rake' => ['1.0.0'])
|
75
|
+
expect(@config.ignore_gem?('rake', '1.0.0')).to be_truthy
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should add and return source' do
|
79
|
+
expect(@config.source).to eq(nil)
|
80
|
+
result = @config.define_source('RubyGems', 'https://rubygems.org') do
|
81
|
+
end
|
82
|
+
expect(result).to be_a(Source)
|
83
|
+
expect(result.gems).to eq([])
|
84
|
+
expect(result.host).to eq('https://rubygems.org')
|
85
|
+
expect(result.name).to eq('rubygems')
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'gemirro/gem'
|
4
|
+
|
5
|
+
# Gem tests
|
6
|
+
module Gemirro
|
7
|
+
describe 'Gem' do
|
8
|
+
before(:each) do
|
9
|
+
@gem = Gem.new('gemirro', '0.0.1')
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should be initialized with string' do
|
13
|
+
gem = Gem.new('gemirro', '0.0.1')
|
14
|
+
expect(gem.name).to eq('gemirro')
|
15
|
+
expect(gem.requirement).to eq(::Gem::Requirement.new(['= 0.0.1']))
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should be initialized with ::Gem::Requirement' do
|
19
|
+
requirement = ::Gem::Requirement.new('0.0.1')
|
20
|
+
gem = Gem.new('gemirro', requirement)
|
21
|
+
expect(gem.name).to eq('gemirro')
|
22
|
+
expect(gem.requirement).to be(requirement)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should return version' do
|
26
|
+
expect(@gem.version).to eq(::Gem::Version.new('0.0.1'))
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should check version' do
|
30
|
+
expect(@gem.version?).to be_truthy
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should return gem filename' do
|
34
|
+
expect(@gem.filename).to eq('gemirro-0.0.1.gem')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'gemirro/source'
|
4
|
+
require 'gemirro/gem'
|
5
|
+
require 'gemirro/versions_file'
|
6
|
+
require 'gemirro/mirror_file'
|
7
|
+
require 'gemirro/gems_fetcher'
|
8
|
+
|
9
|
+
# GemsFetcher tests
|
10
|
+
module Gemirro
|
11
|
+
describe 'GemsFetcher' do
|
12
|
+
include FakeFS::SpecHelpers
|
13
|
+
|
14
|
+
before(:each) do
|
15
|
+
@source = Source.new('RubyGems', 'https://rubygems.org')
|
16
|
+
@versions_file = VersionsFile.new(['0.0.1'])
|
17
|
+
@fetcher = GemsFetcher.new(@source, @versions_file)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should be initialized' do
|
21
|
+
expect(@fetcher.source).to be(@source)
|
22
|
+
expect(@fetcher.versions_file).to be(@versions_file)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should return configuration' do
|
26
|
+
expect(@fetcher.configuration).to be(Gemirro.configuration)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should return logger' do
|
30
|
+
expect(@fetcher.logger).to be(Gemirro.configuration.logger)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should test if gem exists' do
|
34
|
+
@fetcher.configuration.destination = './'
|
35
|
+
expect(@fetcher.gem_exists?('test')).to be_falsy
|
36
|
+
MirrorDirectory.new('./').add_directory('gems')
|
37
|
+
MirrorFile.new('gems/test').write('content')
|
38
|
+
expect(@fetcher.gem_exists?('test')).to be_truthy
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should ignore gem' do
|
42
|
+
expect(@fetcher.ignore_gem?('gemirro', '0.0.1')).to be_falsy
|
43
|
+
@fetcher.configuration.ignore_gem('gemirro', '0.0.1')
|
44
|
+
expect(@fetcher.ignore_gem?('gemirro', '0.0.1')).to be_truthy
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should log error when fetch gem failed' do
|
48
|
+
gem = Gem.new('gemirro')
|
49
|
+
version = ::Gem::Version.new('0.0.1')
|
50
|
+
@source.should_receive(:fetch_gem)
|
51
|
+
.once.with('gemirro', version).and_raise(ArgumentError)
|
52
|
+
@fetcher.logger.should_receive(:error)
|
53
|
+
.once.with(/Failed to retrieve/)
|
54
|
+
@fetcher.logger.should_receive(:debug)
|
55
|
+
.once.with(/Adding (.*) to the list of ignored Gems/)
|
56
|
+
|
57
|
+
expect(@fetcher.fetch_gem(gem, version)).to be_nil
|
58
|
+
expect(@fetcher.ignore_gem?('gemirro', '0.0.1')).to be_truthy
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should fetch gem' do
|
62
|
+
gem = Gem.new('gemirro')
|
63
|
+
version = ::Gem::Version.new('0.0.1')
|
64
|
+
@source.should_receive(:fetch_gem)
|
65
|
+
.once.with('gemirro', version).and_return('gemirro')
|
66
|
+
|
67
|
+
expect(@fetcher.fetch_gem(gem, version)).to eq('gemirro')
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should retrieve versions for specific gem' do
|
71
|
+
gem = Gem.new('gemirro', '0.0.2')
|
72
|
+
@versions_file.should_receive(:versions_for)
|
73
|
+
.once.with('gemirro').and_return(['0.0.1', '0.0.2'])
|
74
|
+
expect(@fetcher.versions_for(gem)).to eq([::Gem::Version.new('0.0.2')])
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should fetch all gems and log debug if gem is not satisfied' do
|
78
|
+
gem = Gem.new('gemirro', '0.0.1')
|
79
|
+
gem.requirement.should_receive(:satisfied_by?)
|
80
|
+
.once.with(nil).and_return(false)
|
81
|
+
@fetcher.source.gems << gem
|
82
|
+
@fetcher.logger.should_receive(:debug)
|
83
|
+
.once.with('Skipping gemirro-0.0.1.gem')
|
84
|
+
expect(@fetcher.fetch).to eq([gem])
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should fetch all gems' do
|
88
|
+
gem = Gem.new('gemirro', '0.0.2')
|
89
|
+
@fetcher.source.gems << gem
|
90
|
+
@fetcher.should_receive(:versions_for).once.and_return(['0.0.2'])
|
91
|
+
gem.requirement.should_receive(:satisfied_by?)
|
92
|
+
.once.with('0.0.2').and_return(true)
|
93
|
+
@fetcher.should_receive(:fetch_gem)
|
94
|
+
.once.with(gem, '0.0.2').and_return('gemfile')
|
95
|
+
@fetcher.configuration.should_receive(:ignore_gem)
|
96
|
+
.once.with('gemirro', '0.0.2')
|
97
|
+
@fetcher.logger.should_receive(:info)
|
98
|
+
.once.with('Fetching gemirro-0.0.2.gem')
|
99
|
+
@fetcher.configuration.mirror_directory.should_receive(:add_file)
|
100
|
+
.once.with('gemirro-0.0.2.gem', 'gemfile')
|
101
|
+
expect(@fetcher.fetch).to eq([gem])
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|