gemstash 1.0.0.pre.1-java → 2.5.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +295 -0
- data/exe/gemstash +3 -0
- data/lib/gemstash/api_key_authorization.rb +32 -0
- data/lib/gemstash/authorization.rb +15 -8
- data/lib/gemstash/cache.rb +42 -2
- data/lib/gemstash/cli/authorize.rb +52 -9
- data/lib/gemstash/cli/base.rb +14 -6
- data/lib/gemstash/cli/setup.rb +67 -39
- data/lib/gemstash/cli/start.rb +6 -2
- data/lib/gemstash/cli/status.rb +3 -1
- data/lib/gemstash/cli/stop.rb +4 -1
- data/lib/gemstash/cli.rb +59 -1
- data/lib/gemstash/config.ru +4 -3
- data/lib/gemstash/configuration.rb +56 -8
- data/lib/gemstash/db/authorization.rb +5 -3
- data/lib/gemstash/db/cached_rubygem.rb +20 -0
- data/lib/gemstash/db/dependency.rb +2 -0
- data/lib/gemstash/db/rubygem.rb +3 -0
- data/lib/gemstash/db/upstream.rb +15 -0
- data/lib/gemstash/db/version.rb +25 -2
- data/lib/gemstash/db.rb +5 -0
- data/lib/gemstash/dependencies.rb +6 -2
- data/lib/gemstash/env.rb +44 -13
- data/lib/gemstash/gem_fetcher.rb +5 -3
- data/lib/gemstash/gem_pusher.rb +25 -18
- data/lib/gemstash/gem_source/dependency_caching.rb +4 -4
- data/lib/gemstash/gem_source/private_source.rb +34 -50
- data/lib/gemstash/gem_source/rack_middleware.rb +3 -0
- data/lib/gemstash/gem_source/upstream_source.rb +71 -27
- data/lib/gemstash/gem_source.rb +4 -2
- data/lib/gemstash/gem_yanker.rb +14 -4
- data/lib/gemstash/health.rb +55 -0
- data/lib/gemstash/http_client.rb +15 -5
- data/lib/gemstash/logging.rb +19 -7
- data/lib/gemstash/man/gemstash-authorize.1 +54 -0
- data/lib/gemstash/man/gemstash-authorize.1.txt +52 -0
- data/lib/gemstash/man/gemstash-configuration.5 +186 -0
- data/lib/gemstash/man/gemstash-configuration.5.txt +208 -0
- data/lib/gemstash/man/gemstash-customize.7 +273 -0
- data/lib/gemstash/man/gemstash-customize.7.txt +184 -0
- data/lib/gemstash/man/gemstash-debugging.7 +30 -0
- data/lib/gemstash/man/gemstash-debugging.7.txt +27 -0
- data/lib/gemstash/man/gemstash-deploy.7 +63 -0
- data/lib/gemstash/man/gemstash-deploy.7.txt +57 -0
- data/lib/gemstash/man/gemstash-mirror.7 +34 -0
- data/lib/gemstash/man/gemstash-mirror.7.txt +31 -0
- data/lib/gemstash/man/gemstash-multiple-sources.7 +131 -0
- data/lib/gemstash/man/gemstash-multiple-sources.7.txt +116 -0
- data/lib/gemstash/man/gemstash-private-gems.7 +191 -0
- data/lib/gemstash/man/gemstash-private-gems.7.txt +154 -0
- data/lib/gemstash/man/gemstash-readme.7 +199 -0
- data/lib/gemstash/man/gemstash-readme.7.txt +177 -0
- data/lib/gemstash/man/gemstash-setup.1 +38 -0
- data/lib/gemstash/man/gemstash-setup.1.txt +38 -0
- data/lib/gemstash/man/gemstash-start.1 +23 -0
- data/lib/gemstash/man/gemstash-start.1.txt +24 -0
- data/lib/gemstash/man/gemstash-status.1 +17 -0
- data/lib/gemstash/man/gemstash-status.1.txt +20 -0
- data/lib/gemstash/man/gemstash-stop.1 +17 -0
- data/lib/gemstash/man/gemstash-stop.1.txt +20 -0
- data/lib/gemstash/man/gemstash-version.1 +17 -0
- data/lib/gemstash/man/gemstash-version.1.txt +19 -0
- data/lib/gemstash/migrations/01_gem_dependencies.rb +11 -9
- data/lib/gemstash/migrations/02_authorizations.rb +4 -2
- data/lib/gemstash/migrations/03_cached_gems.rb +26 -0
- data/lib/gemstash/migrations/04_health_tests.rb +10 -0
- data/lib/gemstash/migrations/05_authorization_names.rb +10 -0
- data/lib/gemstash/puma.rb +5 -3
- data/lib/gemstash/rack_env_rewriter.rb +11 -2
- data/lib/gemstash/specs_builder.rb +25 -15
- data/lib/gemstash/storage.rb +175 -32
- data/lib/gemstash/upstream.rb +43 -8
- data/lib/gemstash/version.rb +4 -2
- data/lib/gemstash/web.rb +13 -8
- data/lib/gemstash.rb +6 -2
- metadata +135 -110
- data/.gitignore +0 -10
- data/.rspec +0 -2
- data/.rubocop-bundler.yml +0 -92
- data/.rubocop-relax.yml +0 -11
- data/.rubocop.yml +0 -8
- data/.travis.yml +0 -20
- data/Gemfile +0 -4
- data/README.md +0 -139
- data/Rakefile +0 -35
- data/bin/console +0 -14
- data/bin/gemstash +0 -3
- data/bin/setup +0 -5
- data/docs/config.md +0 -136
- data/docs/debug.md +0 -24
- data/docs/deploy.md +0 -30
- data/docs/mirror.md +0 -30
- data/docs/multiple_sources.md +0 -68
- data/docs/private_gems.md +0 -140
- data/docs/reference.md +0 -308
- data/gemstash.gemspec +0 -47
- data/gemstash.png +0 -0
- data/lib/gemstash/gem_unyanker.rb +0 -61
data/lib/gemstash/env.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "gemstash"
|
4
|
+
require "active_support/core_ext/file/atomic"
|
2
5
|
require "dalli"
|
3
6
|
require "fileutils"
|
4
7
|
require "sequel"
|
5
8
|
require "uri"
|
9
|
+
require "pathname"
|
6
10
|
|
7
11
|
module Gemstash
|
8
12
|
# Storage for application-wide variables and configuration.
|
@@ -14,7 +18,7 @@ module Gemstash
|
|
14
18
|
|
15
19
|
# Little module to provide easy access to the current Gemstash::Env.
|
16
20
|
module Helper
|
17
|
-
|
21
|
+
private # rubocop:disable Layout/AccessModifierIndentation
|
18
22
|
|
19
23
|
def gemstash_env
|
20
24
|
Gemstash::Env.current
|
@@ -30,6 +34,7 @@ module Gemstash
|
|
30
34
|
|
31
35
|
def call(env)
|
32
36
|
env["gemstash.env"] = @gemstash_env
|
37
|
+
Gemstash::Env.current = @gemstash_env
|
33
38
|
@app.call(env)
|
34
39
|
end
|
35
40
|
end
|
@@ -46,6 +51,7 @@ module Gemstash
|
|
46
51
|
|
47
52
|
def self.current
|
48
53
|
raise EnvNotSetError unless Thread.current[:gemstash_env]
|
54
|
+
|
49
55
|
Thread.current[:gemstash_env]
|
50
56
|
end
|
51
57
|
|
@@ -54,11 +60,9 @@ module Gemstash
|
|
54
60
|
end
|
55
61
|
|
56
62
|
def self.daemonized?
|
57
|
-
if @daemonized.nil?
|
58
|
-
|
59
|
-
|
60
|
-
@daemonized
|
61
|
-
end
|
63
|
+
raise "Daemonized hasn't been set yet!" if @daemonized.nil?
|
64
|
+
|
65
|
+
@daemonized
|
62
66
|
end
|
63
67
|
|
64
68
|
def self.daemonized=(value)
|
@@ -98,8 +102,33 @@ module Gemstash
|
|
98
102
|
File.join(base_path, path)
|
99
103
|
end
|
100
104
|
|
105
|
+
def log_file
|
106
|
+
if config[:log_file] == :stdout
|
107
|
+
$stdout
|
108
|
+
else
|
109
|
+
base_file(config[:log_file] || "server.log")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def pidfile
|
114
|
+
if config[:pidfile]
|
115
|
+
pathname = Pathname.new(config[:pidfile])
|
116
|
+
if pathname.relative?
|
117
|
+
base_file(pathname.to_s)
|
118
|
+
else
|
119
|
+
pathname.to_s
|
120
|
+
end
|
121
|
+
else
|
122
|
+
base_file("puma.pid")
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def atomic_write(file, &block)
|
127
|
+
File.atomic_write(file, File.dirname(file), &block)
|
128
|
+
end
|
129
|
+
|
101
130
|
def rackup
|
102
|
-
File.expand_path("
|
131
|
+
File.expand_path("config.ru", __dir__)
|
103
132
|
end
|
104
133
|
|
105
134
|
def db
|
@@ -108,13 +137,13 @@ module Gemstash
|
|
108
137
|
when "sqlite3"
|
109
138
|
db_path = base_file("gemstash.db")
|
110
139
|
|
111
|
-
if RUBY_PLATFORM == "java"
|
112
|
-
|
140
|
+
db = if RUBY_PLATFORM == "java"
|
141
|
+
Sequel.connect("jdbc:sqlite:#{db_path}", config.database_connection_config)
|
113
142
|
else
|
114
|
-
|
143
|
+
Sequel.connect("sqlite://#{CGI.escape(db_path)}", config.database_connection_config)
|
115
144
|
end
|
116
|
-
when "postgres"
|
117
|
-
db = Sequel.connect(config[:db_url])
|
145
|
+
when "postgres", "mysql", "mysql2"
|
146
|
+
db = Sequel.connect(config[:db_url], config.database_connection_config)
|
118
147
|
else
|
119
148
|
raise "Unsupported DB adapter: '#{config[:db_adapter]}'"
|
120
149
|
end
|
@@ -126,7 +155,7 @@ module Gemstash
|
|
126
155
|
|
127
156
|
def self.migrate(db)
|
128
157
|
Sequel.extension :migration
|
129
|
-
migrations_dir = File.expand_path("
|
158
|
+
migrations_dir = File.expand_path("migrations", __dir__)
|
130
159
|
Sequel::Migrator.run(db, migrations_dir, :use_transactions => true)
|
131
160
|
end
|
132
161
|
|
@@ -141,6 +170,8 @@ module Gemstash
|
|
141
170
|
Gemstash::LruReduxClient.new
|
142
171
|
when "memcached"
|
143
172
|
Dalli::Client.new(config[:memcached_servers])
|
173
|
+
when "redis"
|
174
|
+
Gemstash::RedisClient.new(config[:redis_servers])
|
144
175
|
else
|
145
176
|
raise "Invalid cache client: '#{config[:cache_type]}'"
|
146
177
|
end
|
data/lib/gemstash/gem_fetcher.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "gemstash"
|
2
4
|
require "set"
|
3
5
|
|
4
6
|
module Gemstash
|
5
|
-
|
7
|
+
# :nodoc:
|
6
8
|
class GemFetcher
|
7
9
|
def initialize(http_client)
|
8
10
|
@http_client = http_client
|
9
|
-
@valid_headers = Set.new([
|
11
|
+
@valid_headers = Set.new(%w[etag content-type content-length last-modified])
|
10
12
|
end
|
11
13
|
|
12
14
|
def fetch(gem_id, type, &block)
|
@@ -31,7 +33,7 @@ module Gemstash
|
|
31
33
|
end
|
32
34
|
|
33
35
|
def filter_headers(headers)
|
34
|
-
headers.inject({}) do|properties, (key, value)|
|
36
|
+
headers.inject({}) do |properties, (key, value)|
|
35
37
|
properties[key.downcase] = value if @valid_headers.include?(key.downcase)
|
36
38
|
properties
|
37
39
|
end
|
data/lib/gemstash/gem_pusher.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "gemstash"
|
2
4
|
require "rubygems/package"
|
3
5
|
require "stringio"
|
4
6
|
|
5
|
-
|
7
|
+
# :nodoc:
|
6
8
|
module Gemstash
|
7
9
|
# Class that supports pushing a new gem to the private repository of gems.
|
8
10
|
class GemPusher
|
@@ -16,12 +18,17 @@ module Gemstash
|
|
16
18
|
class YankedVersionError < ExistingVersionError
|
17
19
|
end
|
18
20
|
|
19
|
-
def
|
20
|
-
|
21
|
+
def self.serve(app)
|
22
|
+
gem = app.request.body.read
|
23
|
+
new(app.auth, gem).serve
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(auth, content)
|
27
|
+
@auth = auth
|
21
28
|
@content = content
|
22
29
|
end
|
23
30
|
|
24
|
-
def
|
31
|
+
def serve
|
25
32
|
check_auth
|
26
33
|
store_gem
|
27
34
|
store_gemspec
|
@@ -44,10 +51,15 @@ module Gemstash
|
|
44
51
|
end
|
45
52
|
|
46
53
|
def check_auth
|
47
|
-
|
54
|
+
@auth.check("push")
|
48
55
|
end
|
49
56
|
|
50
57
|
def store_gem
|
58
|
+
resource_exist = storage.resource(full_name).exist?
|
59
|
+
resource_is_indexed = storage.resource(full_name).properties[:indexed] if resource_exist
|
60
|
+
|
61
|
+
raise ExistingVersionError, "Cannot push to an existing version!" if resource_exist && resource_is_indexed
|
62
|
+
|
51
63
|
storage.resource(full_name).save({ gem: @content }, indexed: true)
|
52
64
|
end
|
53
65
|
|
@@ -64,14 +76,8 @@ module Gemstash
|
|
64
76
|
gemstash_env.db.transaction do
|
65
77
|
gem_id = Gemstash::DB::Rubygem.find_or_insert(spec)
|
66
78
|
existing = Gemstash::DB::Version.find_by_spec(gem_id, spec)
|
67
|
-
|
68
|
-
if existing
|
69
|
-
if existing.indexed
|
70
|
-
raise ExistingVersionError, "Cannot push to an existing version!"
|
71
|
-
else
|
72
|
-
raise YankedVersionError, "Cannot push to a yanked version!"
|
73
|
-
end
|
74
|
-
end
|
79
|
+
raise ExistingVersionError, "Cannot push to an existing version!" if existing && existing.indexed
|
80
|
+
raise YankedVersionError, "Cannot push to a yanked version!" if existing && !existing.indexed
|
75
81
|
|
76
82
|
version_id = Gemstash::DB::Version.insert_by_spec(gem_id, spec)
|
77
83
|
Gemstash::DB::Dependency.insert_by_spec(version_id, spec)
|
@@ -90,14 +96,14 @@ module Gemstash
|
|
90
96
|
module LegacyRubyGemsSupport
|
91
97
|
def self.included(base)
|
92
98
|
base.class_eval do
|
93
|
-
alias_method :
|
94
|
-
remove_method :
|
99
|
+
alias_method :serve_without_cleanup, :serve
|
100
|
+
remove_method :serve
|
95
101
|
remove_method :gem
|
96
102
|
end
|
97
103
|
end
|
98
104
|
|
99
|
-
def
|
100
|
-
|
105
|
+
def serve
|
106
|
+
serve_without_cleanup
|
101
107
|
ensure
|
102
108
|
cleanup
|
103
109
|
end
|
@@ -115,11 +121,12 @@ module Gemstash
|
|
115
121
|
|
116
122
|
def cleanup
|
117
123
|
return unless @tempfile
|
124
|
+
|
118
125
|
@tempfile.close
|
119
126
|
@tempfile.unlink
|
120
127
|
end
|
121
128
|
end
|
122
129
|
|
123
|
-
GemPusher.
|
130
|
+
GemPusher.include LegacyRubyGemsSupport
|
124
131
|
end
|
125
132
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Gemstash
|
2
4
|
module GemSource
|
3
5
|
# Module for caching dependencies in a GemSource.
|
@@ -7,9 +9,7 @@ module Gemstash
|
|
7
9
|
def serve_dependencies
|
8
10
|
gems = gems_from_params
|
9
11
|
|
10
|
-
if gems.length > API_REQUEST_LIMIT
|
11
|
-
halt 422, "Too many gems (use --full-index instead)"
|
12
|
-
end
|
12
|
+
halt 422, "Too many gems (use --full-index instead)" if gems.length > API_REQUEST_LIMIT
|
13
13
|
|
14
14
|
content_type "application/octet-stream"
|
15
15
|
Marshal.dump dependencies.fetch(gems)
|
@@ -21,7 +21,7 @@ module Gemstash
|
|
21
21
|
if gems.length > API_REQUEST_LIMIT
|
22
22
|
halt 422, {
|
23
23
|
"error" => "Too many gems (use --full-index instead)",
|
24
|
-
"code"
|
24
|
+
"code" => 422
|
25
25
|
}.to_json
|
26
26
|
end
|
27
27
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "gemstash"
|
2
4
|
|
3
5
|
module Gemstash
|
@@ -6,6 +8,7 @@ module Gemstash
|
|
6
8
|
class PrivateSource < Gemstash::GemSource::Base
|
7
9
|
include Gemstash::GemSource::DependencyCaching
|
8
10
|
include Gemstash::Env::Helper
|
11
|
+
attr_accessor :auth
|
9
12
|
|
10
13
|
def self.rack_env_rewriter
|
11
14
|
@rack_env_rewriter ||= Gemstash::RackEnvRewriter.new(%r{\A/private})
|
@@ -14,6 +17,7 @@ module Gemstash
|
|
14
17
|
def self.matches?(env)
|
15
18
|
rewriter = rack_env_rewriter.for(env)
|
16
19
|
return false unless rewriter.matches?
|
20
|
+
|
17
21
|
rewriter.rewrite
|
18
22
|
true
|
19
23
|
end
|
@@ -23,27 +27,11 @@ module Gemstash
|
|
23
27
|
end
|
24
28
|
|
25
29
|
def serve_add_gem
|
26
|
-
|
27
|
-
auth = request.env["HTTP_AUTHORIZATION"]
|
28
|
-
gem = request.body.read
|
29
|
-
Gemstash::GemPusher.new(auth, gem).push
|
30
|
-
end
|
30
|
+
protected(Gemstash::GemPusher)
|
31
31
|
end
|
32
32
|
|
33
33
|
def serve_yank
|
34
|
-
|
35
|
-
auth = request.env["HTTP_AUTHORIZATION"]
|
36
|
-
gem_name = params[:gem_name]
|
37
|
-
Gemstash::GemYanker.new(auth, gem_name, slug_param).yank
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def serve_unyank
|
42
|
-
authenticated("Gemstash Private Gems") do
|
43
|
-
auth = request.env["HTTP_AUTHORIZATION"]
|
44
|
-
gem_name = params[:gem_name]
|
45
|
-
Gemstash::GemUnyanker.new(auth, gem_name, slug_param).unyank
|
46
|
-
end
|
34
|
+
protected(Gemstash::GemYanker)
|
47
35
|
end
|
48
36
|
|
49
37
|
def serve_add_spec_json
|
@@ -59,7 +47,7 @@ module Gemstash
|
|
59
47
|
end
|
60
48
|
|
61
49
|
def serve_versions
|
62
|
-
halt
|
50
|
+
halt 404, "Not yet supported"
|
63
51
|
end
|
64
52
|
|
65
53
|
def serve_info(name)
|
@@ -67,11 +55,14 @@ module Gemstash
|
|
67
55
|
end
|
68
56
|
|
69
57
|
def serve_marshal(id)
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
58
|
+
authorization.protect(self) do
|
59
|
+
auth.check("fetch") if gemstash_env.config[:protected_fetch]
|
60
|
+
gem_full_name = id.delete_suffix(".gemspec.rz")
|
61
|
+
gem = fetch_gem(gem_full_name)
|
62
|
+
halt 404 unless gem.exist?(:spec)
|
63
|
+
content_type "application/octet-stream"
|
64
|
+
gem.content(:spec)
|
65
|
+
end
|
75
66
|
end
|
76
67
|
|
77
68
|
def serve_actual_gem(id)
|
@@ -79,44 +70,38 @@ module Gemstash
|
|
79
70
|
end
|
80
71
|
|
81
72
|
def serve_gem(id)
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
73
|
+
authorization.protect(self) do
|
74
|
+
auth.check("fetch") if gemstash_env.config[:protected_fetch]
|
75
|
+
gem_full_name = id.delete_suffix(".gem")
|
76
|
+
gem = fetch_gem(gem_full_name)
|
77
|
+
content_type "application/octet-stream"
|
78
|
+
gem.content(:gem)
|
79
|
+
end
|
86
80
|
end
|
87
81
|
|
88
|
-
def
|
89
|
-
|
82
|
+
def serve_specs
|
83
|
+
params[:prerelease] = false
|
84
|
+
protected(Gemstash::SpecsBuilder)
|
90
85
|
end
|
91
86
|
|
92
|
-
def
|
93
|
-
|
94
|
-
Gemstash::SpecsBuilder
|
87
|
+
def serve_latest_specs
|
88
|
+
params[:latest] = true
|
89
|
+
protected(Gemstash::SpecsBuilder)
|
95
90
|
end
|
96
91
|
|
97
92
|
def serve_prerelease_specs
|
98
|
-
|
99
|
-
Gemstash::SpecsBuilder
|
93
|
+
params[:prerelease] = true
|
94
|
+
protected(Gemstash::SpecsBuilder)
|
100
95
|
end
|
101
96
|
|
102
97
|
private
|
103
98
|
|
104
|
-
def
|
105
|
-
|
106
|
-
platform = params[:platform]
|
107
|
-
|
108
|
-
if platform.to_s.empty?
|
109
|
-
version
|
110
|
-
else
|
111
|
-
"#{version}-#{platform}"
|
112
|
-
end
|
99
|
+
def protected(servable)
|
100
|
+
authorization.protect(self) { servable.serve(self) }
|
113
101
|
end
|
114
102
|
|
115
|
-
def
|
116
|
-
|
117
|
-
rescue Gemstash::NotAuthorizedError => e
|
118
|
-
headers["WWW-Authenticate"] = "Basic realm=\"#{realm}\""
|
119
|
-
halt 401, e.message
|
103
|
+
def authorization
|
104
|
+
Gemstash::ApiKeyAuthorization
|
120
105
|
end
|
121
106
|
|
122
107
|
def dependencies
|
@@ -130,7 +115,6 @@ module Gemstash
|
|
130
115
|
def fetch_gem(gem_full_name)
|
131
116
|
gem = storage.resource(gem_full_name)
|
132
117
|
halt 404 unless gem.exist?(:gem)
|
133
|
-
gem.load(:gem)
|
134
118
|
halt 403, "That gem has been yanked" unless gem.properties[:indexed]
|
135
119
|
gem
|
136
120
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "gemstash"
|
2
4
|
|
3
5
|
module Gemstash
|
@@ -11,6 +13,7 @@ module Gemstash
|
|
11
13
|
def call(env)
|
12
14
|
Gemstash::GemSource.sources.each do |source|
|
13
15
|
next unless source.matches?(env)
|
16
|
+
|
14
17
|
env["gemstash.gem_source"] = source
|
15
18
|
break
|
16
19
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "gemstash"
|
2
4
|
require "cgi"
|
3
5
|
|
@@ -12,6 +14,7 @@ module Gemstash
|
|
12
14
|
def self.matches?(env)
|
13
15
|
rewriter = rack_env_rewriter.for(env)
|
14
16
|
return false unless rewriter.matches?
|
17
|
+
|
15
18
|
rewriter.rewrite
|
16
19
|
env["gemstash.upstream"] = rewriter.captures["upstream_url"]
|
17
20
|
capture_user_agent(env)
|
@@ -35,10 +38,6 @@ module Gemstash
|
|
35
38
|
halt 403, "Cannot yank from an upstream server!"
|
36
39
|
end
|
37
40
|
|
38
|
-
def serve_unyank
|
39
|
-
halt 403, "Cannot unyank from an upstream server!"
|
40
|
-
end
|
41
|
-
|
42
41
|
def serve_add_spec_json
|
43
42
|
halt 403, "Cannot add spec to an upstream server!"
|
44
43
|
end
|
@@ -60,11 +59,11 @@ module Gemstash
|
|
60
59
|
end
|
61
60
|
|
62
61
|
def serve_versions
|
63
|
-
redirect
|
62
|
+
redirect index_upstream.url("versions", request.query_string)
|
64
63
|
end
|
65
64
|
|
66
65
|
def serve_info(name)
|
67
|
-
redirect
|
66
|
+
redirect index_upstream.url("info/#{name}", request.query_string)
|
68
67
|
end
|
69
68
|
|
70
69
|
def serve_marshal(id)
|
@@ -94,8 +93,21 @@ module Gemstash
|
|
94
93
|
private
|
95
94
|
|
96
95
|
def upstream
|
97
|
-
@upstream ||= Gemstash::Upstream.new(
|
98
|
-
|
96
|
+
@upstream ||= Gemstash::Upstream.new(
|
97
|
+
env["gemstash.upstream"],
|
98
|
+
user_agent: env["gemstash.user-agent"]
|
99
|
+
)
|
100
|
+
end
|
101
|
+
|
102
|
+
def index_upstream
|
103
|
+
@index_upstream ||=
|
104
|
+
if upstream.uri.host == "rubygems.org"
|
105
|
+
uri = upstream.uri.dup
|
106
|
+
uri.host = "index.rubygems.org"
|
107
|
+
Gemstash::Upstream.new(uri, user_agent: upstream.user_agent)
|
108
|
+
else
|
109
|
+
upstream
|
110
|
+
end
|
99
111
|
end
|
100
112
|
end
|
101
113
|
|
@@ -116,16 +128,40 @@ module Gemstash
|
|
116
128
|
serve_cached(id, :gem)
|
117
129
|
end
|
118
130
|
|
131
|
+
def serve_latest_specs
|
132
|
+
http_client = http_client_for(upstream)
|
133
|
+
http_client.get("latest_specs.4.8.gz")
|
134
|
+
end
|
135
|
+
|
136
|
+
def serve_prerelease_specs
|
137
|
+
http_client = http_client_for(upstream)
|
138
|
+
http_client.get("prerelease_specs.4.8.gz")
|
139
|
+
end
|
140
|
+
|
141
|
+
def serve_specs
|
142
|
+
http_client = http_client_for(upstream)
|
143
|
+
http_client.get("specs.4.8.gz")
|
144
|
+
end
|
145
|
+
|
119
146
|
private
|
120
147
|
|
121
|
-
def serve_cached(id,
|
122
|
-
gem = fetch_gem(id,
|
123
|
-
|
124
|
-
gem.content(
|
148
|
+
def serve_cached(id, resource_type)
|
149
|
+
gem = fetch_gem(id, resource_type)
|
150
|
+
set_gem_headers(gem, resource_type)
|
151
|
+
gem.content(resource_type)
|
125
152
|
rescue Gemstash::WebError => e
|
126
153
|
halt e.code
|
127
154
|
end
|
128
155
|
|
156
|
+
def set_gem_headers(gem, resource_type)
|
157
|
+
return unless gem.property?(:headers, resource_type)
|
158
|
+
|
159
|
+
gem_headers = gem.properties[:headers][resource_type]
|
160
|
+
headers["Content-Type"] = gem_headers["content-type"] if gem_headers.include?("content-type")
|
161
|
+
headers["Last-Modified"] = gem_headers["last-modified"] if gem_headers.include?("last-modified")
|
162
|
+
headers["ETag"] = gem_headers["etag"] if gem_headers.include?("etag")
|
163
|
+
end
|
164
|
+
|
129
165
|
def dependencies
|
130
166
|
@dependencies ||= begin
|
131
167
|
http_client = http_client_for(upstream)
|
@@ -142,25 +178,33 @@ module Gemstash
|
|
142
178
|
@gem_fetcher ||= Gemstash::GemFetcher.new(http_client_for(upstream))
|
143
179
|
end
|
144
180
|
|
145
|
-
def fetch_gem(id,
|
181
|
+
def fetch_gem(id, resource_type)
|
146
182
|
gem_name = Gemstash::Upstream::GemName.new(upstream, id)
|
147
183
|
gem_resource = storage.resource(gem_name.name)
|
148
|
-
if gem_resource.exist?(
|
149
|
-
fetch_local_gem(gem_name, gem_resource,
|
184
|
+
if gem_resource.exist?(resource_type)
|
185
|
+
fetch_local_gem(gem_name, gem_resource, resource_type)
|
150
186
|
else
|
151
|
-
fetch_remote_gem(gem_name, gem_resource,
|
187
|
+
fetch_remote_gem(gem_name, gem_resource, resource_type)
|
152
188
|
end
|
153
189
|
end
|
154
190
|
|
155
|
-
def fetch_local_gem(gem_name, gem_resource,
|
156
|
-
log.info "Gem #{gem_name.name} exists, returning cached #{
|
157
|
-
gem_resource
|
191
|
+
def fetch_local_gem(gem_name, gem_resource, resource_type)
|
192
|
+
log.info "Gem #{gem_name.name} exists, returning cached #{resource_type}"
|
193
|
+
gem_resource
|
158
194
|
end
|
159
195
|
|
160
|
-
def fetch_remote_gem(gem_name, gem_resource,
|
161
|
-
log.info "Gem #{gem_name.name} is not cached, fetching #{
|
162
|
-
gem_fetcher.fetch(gem_name.id,
|
163
|
-
|
196
|
+
def fetch_remote_gem(gem_name, gem_resource, resource_type)
|
197
|
+
log.info "Gem #{gem_name.name} is not cached, fetching #{resource_type}"
|
198
|
+
gem_fetcher.fetch(gem_name.id, resource_type) do |content, properties|
|
199
|
+
resource_properties = {
|
200
|
+
upstream: upstream.to_s,
|
201
|
+
gem_name: gem_name.name,
|
202
|
+
headers: { resource_type => properties }
|
203
|
+
}
|
204
|
+
|
205
|
+
gem = gem_resource.save({ resource_type => content }, resource_properties)
|
206
|
+
Gemstash::DB::CachedRubygem.store(upstream, gem_name, resource_type)
|
207
|
+
gem
|
164
208
|
end
|
165
209
|
end
|
166
210
|
end
|
@@ -169,13 +213,13 @@ module Gemstash
|
|
169
213
|
# default upstream).
|
170
214
|
class RubygemsSource < Gemstash::GemSource::UpstreamSource
|
171
215
|
def self.matches?(env)
|
172
|
-
if env["HTTP_X_GEMFILE_SOURCE"].to_s.empty?
|
173
|
-
env["gemstash.
|
216
|
+
env["gemstash.upstream"] = if env["gemstash.env"].config[:ignore_gemfile_source] || env["HTTP_X_GEMFILE_SOURCE"].to_s.empty?
|
217
|
+
env["gemstash.env"].config[:rubygems_url]
|
174
218
|
else
|
175
|
-
env["
|
219
|
+
env["HTTP_X_GEMFILE_SOURCE"]
|
176
220
|
end
|
177
|
-
capture_user_agent(env)
|
178
221
|
|
222
|
+
capture_user_agent(env)
|
179
223
|
true
|
180
224
|
end
|
181
225
|
end
|
data/lib/gemstash/gem_source.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "gemstash"
|
2
4
|
require "forwardable"
|
3
5
|
|
4
6
|
module Gemstash
|
5
|
-
|
7
|
+
# :nodoc:
|
6
8
|
module GemSource
|
7
9
|
autoload :DependencyCaching, "gemstash/gem_source/dependency_caching"
|
8
10
|
autoload :PrivateSource, "gemstash/gem_source/private_source"
|
@@ -27,7 +29,7 @@ module Gemstash
|
|
27
29
|
include Gemstash::Logging
|
28
30
|
|
29
31
|
def_delegators :@app, :cache_control, :content_type, :env, :halt,
|
30
|
-
|
32
|
+
:headers, :http_client_for, :params, :redirect, :request
|
31
33
|
|
32
34
|
def initialize(app)
|
33
35
|
@app = app
|
data/lib/gemstash/gem_yanker.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "gemstash"
|
2
4
|
|
3
5
|
module Gemstash
|
@@ -17,13 +19,19 @@ module Gemstash
|
|
17
19
|
class YankedVersionError < StandardError
|
18
20
|
end
|
19
21
|
|
20
|
-
def
|
21
|
-
|
22
|
+
def self.serve(app)
|
23
|
+
gem_name = app.params[:gem_name]
|
24
|
+
slug = Gemstash::DB::Version.slug(app.params)
|
25
|
+
new(app.auth, gem_name, slug).serve
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(auth, gem_name, slug)
|
29
|
+
@auth = auth
|
22
30
|
@gem_name = gem_name
|
23
31
|
@slug = slug
|
24
32
|
end
|
25
33
|
|
26
|
-
def
|
34
|
+
def serve
|
27
35
|
check_auth
|
28
36
|
update_database
|
29
37
|
invalidate_cache
|
@@ -40,15 +48,17 @@ module Gemstash
|
|
40
48
|
end
|
41
49
|
|
42
50
|
def check_auth
|
43
|
-
|
51
|
+
@auth.check("yank")
|
44
52
|
end
|
45
53
|
|
46
54
|
def update_database
|
47
55
|
gemstash_env.db.transaction do
|
48
56
|
raise UnknownGemError, "Cannot yank an unknown gem!" unless Gemstash::DB::Rubygem[name: @gem_name]
|
57
|
+
|
49
58
|
version = Gemstash::DB::Version.find_by_full_name(full_name)
|
50
59
|
raise UnknownVersionError, "Cannot yank an unknown version!" unless version
|
51
60
|
raise YankedVersionError, "Cannot yank an already yanked version!" unless version.indexed
|
61
|
+
|
52
62
|
version.deindex
|
53
63
|
storage.resource(version.storage_id).update_properties(indexed: false)
|
54
64
|
end
|