gemstash 1.0.0.pre.1-java → 2.6.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +303 -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 +61 -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
|