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.
Files changed (99) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +303 -0
  3. data/exe/gemstash +3 -0
  4. data/lib/gemstash/api_key_authorization.rb +32 -0
  5. data/lib/gemstash/authorization.rb +15 -8
  6. data/lib/gemstash/cache.rb +42 -2
  7. data/lib/gemstash/cli/authorize.rb +52 -9
  8. data/lib/gemstash/cli/base.rb +14 -6
  9. data/lib/gemstash/cli/setup.rb +67 -39
  10. data/lib/gemstash/cli/start.rb +6 -2
  11. data/lib/gemstash/cli/status.rb +3 -1
  12. data/lib/gemstash/cli/stop.rb +4 -1
  13. data/lib/gemstash/cli.rb +59 -1
  14. data/lib/gemstash/config.ru +4 -3
  15. data/lib/gemstash/configuration.rb +61 -8
  16. data/lib/gemstash/db/authorization.rb +5 -3
  17. data/lib/gemstash/db/cached_rubygem.rb +20 -0
  18. data/lib/gemstash/db/dependency.rb +2 -0
  19. data/lib/gemstash/db/rubygem.rb +3 -0
  20. data/lib/gemstash/db/upstream.rb +15 -0
  21. data/lib/gemstash/db/version.rb +25 -2
  22. data/lib/gemstash/db.rb +5 -0
  23. data/lib/gemstash/dependencies.rb +6 -2
  24. data/lib/gemstash/env.rb +44 -13
  25. data/lib/gemstash/gem_fetcher.rb +5 -3
  26. data/lib/gemstash/gem_pusher.rb +25 -18
  27. data/lib/gemstash/gem_source/dependency_caching.rb +4 -4
  28. data/lib/gemstash/gem_source/private_source.rb +34 -50
  29. data/lib/gemstash/gem_source/rack_middleware.rb +3 -0
  30. data/lib/gemstash/gem_source/upstream_source.rb +71 -27
  31. data/lib/gemstash/gem_source.rb +4 -2
  32. data/lib/gemstash/gem_yanker.rb +14 -4
  33. data/lib/gemstash/health.rb +55 -0
  34. data/lib/gemstash/http_client.rb +15 -5
  35. data/lib/gemstash/logging.rb +19 -7
  36. data/lib/gemstash/man/gemstash-authorize.1 +54 -0
  37. data/lib/gemstash/man/gemstash-authorize.1.txt +52 -0
  38. data/lib/gemstash/man/gemstash-configuration.5 +186 -0
  39. data/lib/gemstash/man/gemstash-configuration.5.txt +208 -0
  40. data/lib/gemstash/man/gemstash-customize.7 +273 -0
  41. data/lib/gemstash/man/gemstash-customize.7.txt +184 -0
  42. data/lib/gemstash/man/gemstash-debugging.7 +30 -0
  43. data/lib/gemstash/man/gemstash-debugging.7.txt +27 -0
  44. data/lib/gemstash/man/gemstash-deploy.7 +63 -0
  45. data/lib/gemstash/man/gemstash-deploy.7.txt +57 -0
  46. data/lib/gemstash/man/gemstash-mirror.7 +34 -0
  47. data/lib/gemstash/man/gemstash-mirror.7.txt +31 -0
  48. data/lib/gemstash/man/gemstash-multiple-sources.7 +131 -0
  49. data/lib/gemstash/man/gemstash-multiple-sources.7.txt +116 -0
  50. data/lib/gemstash/man/gemstash-private-gems.7 +191 -0
  51. data/lib/gemstash/man/gemstash-private-gems.7.txt +154 -0
  52. data/lib/gemstash/man/gemstash-readme.7 +199 -0
  53. data/lib/gemstash/man/gemstash-readme.7.txt +177 -0
  54. data/lib/gemstash/man/gemstash-setup.1 +38 -0
  55. data/lib/gemstash/man/gemstash-setup.1.txt +38 -0
  56. data/lib/gemstash/man/gemstash-start.1 +23 -0
  57. data/lib/gemstash/man/gemstash-start.1.txt +24 -0
  58. data/lib/gemstash/man/gemstash-status.1 +17 -0
  59. data/lib/gemstash/man/gemstash-status.1.txt +20 -0
  60. data/lib/gemstash/man/gemstash-stop.1 +17 -0
  61. data/lib/gemstash/man/gemstash-stop.1.txt +20 -0
  62. data/lib/gemstash/man/gemstash-version.1 +17 -0
  63. data/lib/gemstash/man/gemstash-version.1.txt +19 -0
  64. data/lib/gemstash/migrations/01_gem_dependencies.rb +11 -9
  65. data/lib/gemstash/migrations/02_authorizations.rb +4 -2
  66. data/lib/gemstash/migrations/03_cached_gems.rb +26 -0
  67. data/lib/gemstash/migrations/04_health_tests.rb +10 -0
  68. data/lib/gemstash/migrations/05_authorization_names.rb +10 -0
  69. data/lib/gemstash/puma.rb +5 -3
  70. data/lib/gemstash/rack_env_rewriter.rb +11 -2
  71. data/lib/gemstash/specs_builder.rb +25 -15
  72. data/lib/gemstash/storage.rb +175 -32
  73. data/lib/gemstash/upstream.rb +43 -8
  74. data/lib/gemstash/version.rb +4 -2
  75. data/lib/gemstash/web.rb +13 -8
  76. data/lib/gemstash.rb +6 -2
  77. metadata +135 -110
  78. data/.gitignore +0 -10
  79. data/.rspec +0 -2
  80. data/.rubocop-bundler.yml +0 -92
  81. data/.rubocop-relax.yml +0 -11
  82. data/.rubocop.yml +0 -8
  83. data/.travis.yml +0 -20
  84. data/Gemfile +0 -4
  85. data/README.md +0 -139
  86. data/Rakefile +0 -35
  87. data/bin/console +0 -14
  88. data/bin/gemstash +0 -3
  89. data/bin/setup +0 -5
  90. data/docs/config.md +0 -136
  91. data/docs/debug.md +0 -24
  92. data/docs/deploy.md +0 -30
  93. data/docs/mirror.md +0 -30
  94. data/docs/multiple_sources.md +0 -68
  95. data/docs/private_gems.md +0 -140
  96. data/docs/reference.md +0 -308
  97. data/gemstash.gemspec +0 -47
  98. data/gemstash.png +0 -0
  99. data/lib/gemstash/gem_unyanker.rb +0 -61
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "gemstash"
2
4
 
3
5
  module Gemstash
@@ -21,25 +23,31 @@ module Gemstash
21
23
  end
22
24
 
23
25
  def check_rubygems_version
24
- @cli.say(@cli.set_color("Rubygems version is too old, " \
25
- "please update rubygems by running: " \
26
- "gem update --system", :red)) unless
27
- Gem::Requirement.new(">= 2.4").satisfied_by?(Gem::Version.new(Gem::VERSION))
26
+ unless Gem::Requirement.new(">= 2.4").satisfied_by?(Gem::Version.new(Gem::VERSION))
27
+ @cli.say(@cli.set_color("Rubygems version is too old, " \
28
+ "please update rubygems by running: " \
29
+ "gem update --system", :red))
30
+ end
28
31
  end
29
32
 
30
33
  def store_config
31
34
  config = Gemstash::Configuration.new(file: @cli.options[:config_file])
32
35
  gemstash_env.config = config
36
+ rescue Gemstash::Configuration::MissingFileError => e
37
+ raise Gemstash::CLI::Error.new(@cli, e.message)
33
38
  end
34
39
 
35
40
  def check_gemstash_version
36
41
  version = Gem::Version.new(Gemstash::Storage.metadata[:gemstash_version])
37
42
  return if Gem::Requirement.new("<= #{Gemstash::VERSION}").satisfied_by?(Gem::Version.new(version))
38
- raise Gemstash::CLI::Error.new(@cli, "Gemstash version is too old")
43
+
44
+ raise Gemstash::CLI::Error.new(@cli, "Gemstash version #{Gemstash::VERSION} does not support version " \
45
+ "#{version}.\nIt appears you may have downgraded Gemstash, please " \
46
+ "install version #{version} or later.")
39
47
  end
40
48
 
41
49
  def pidfile_args
42
- ["--pidfile", gemstash_env.base_file("puma.pid")]
50
+ ["--pidfile", gemstash_env.pidfile]
43
51
  end
44
52
  end
45
53
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "gemstash"
2
4
  require "fileutils"
3
5
  require "yaml"
@@ -22,6 +24,8 @@ module Gemstash
22
24
  ask_storage
23
25
  ask_cache
24
26
  ask_database
27
+ ask_protected_fetch
28
+ ask_timeout
25
29
  check_cache
26
30
  check_storage
27
31
  check_database
@@ -42,9 +46,27 @@ module Gemstash
42
46
 
43
47
  def say_current_config(option, label)
44
48
  return if gemstash_env.config.default?(option)
49
+
45
50
  @cli.say "#{label}: #{gemstash_env.config[option]}"
46
51
  end
47
52
 
53
+ def ask_with_default(prompt, options, default)
54
+ raise "The options must all be lower case" if options.any? {|x| x.downcase != x }
55
+
56
+ result = nil
57
+ displayed_options = options.map {|x| x == default ? x.upcase : x }
58
+ prompt = "#{prompt} [#{displayed_options.join(", ")}]"
59
+
60
+ until result
61
+ result = @cli.ask prompt
62
+ result = result.downcase
63
+ result = default if result.empty?
64
+ result = nil unless options.include?(result)
65
+ end
66
+
67
+ result
68
+ end
69
+
48
70
  def ask_storage
49
71
  say_current_config(:base_path, "Current base path")
50
72
  path = @cli.ask "Where should files go? [~/.gemstash]", path: true
@@ -54,18 +76,9 @@ module Gemstash
54
76
 
55
77
  def ask_cache
56
78
  say_current_config(:cache_type, "Current cache")
57
- options = %w(memory memcached)
58
- cache = nil
59
-
60
- until cache
61
- cache = @cli.ask "Cache with what? [MEMORY, memcached]"
62
- cache = cache.downcase
63
- cache = "memory" if cache.empty?
64
- cache = nil unless options.include?(cache)
65
- end
66
-
67
- @config[:cache_type] = cache
68
- ask_memcached_details if cache == "memcached"
79
+ @config[:cache_type] = ask_with_default("Cache with what?", %w[memory memcached redis], "memory")
80
+ ask_memcached_details if @config[:cache_type] == "memcached"
81
+ ask_redis_details if @config[:cache_type] == "redis"
69
82
  end
70
83
 
71
84
  def ask_memcached_details
@@ -75,29 +88,26 @@ module Gemstash
75
88
  @config[:memcached_servers] = servers
76
89
  end
77
90
 
91
+ def ask_redis_details
92
+ say_current_config(:redis_servers, "Current Redis servers")
93
+ servers = @cli.ask "What is the comma-separated list of Redis servers? [localhost:6379]"
94
+ servers = "localhost:6379" if servers.empty?
95
+ @config[:redis_servers] = servers
96
+ end
97
+
78
98
  def ask_database
79
99
  say_current_config(:db_adapter, "Current database adapter")
80
- options = %w(sqlite3 postgres)
81
- database = nil
82
-
83
- until database
84
- database = @cli.ask "What database adapter? [SQLITE3, postgres]"
85
- database = database.downcase
86
- database = "sqlite3" if database.empty?
87
- database = nil unless options.include?(database)
88
- end
89
-
90
- @config[:db_adapter] = database
91
- ask_postgres_details if database == "postgres"
100
+ @config[:db_adapter] = ask_with_default("What database adapter?", %w[sqlite3 postgres mysql mysql2], "sqlite3")
101
+ ask_database_details(@config[:db_adapter]) unless @config[:db_adapter] == "sqlite3"
92
102
  end
93
103
 
94
- def ask_postgres_details
104
+ def ask_database_details(database)
95
105
  say_current_config(:db_url, "Current database url")
96
106
 
97
- if RUBY_PLATFORM == "java"
98
- default_value = "jdbc:postgres:///gemstash"
107
+ default_value = if RUBY_PLATFORM == "java"
108
+ "jdbc:#{database}:///gemstash"
99
109
  else
100
- default_value = "postgres:///gemstash"
110
+ "#{database}:///gemstash"
101
111
  end
102
112
 
103
113
  url = @cli.ask "Where is the database? [#{default_value}]"
@@ -105,20 +115,27 @@ module Gemstash
105
115
  @config[:db_url] = url
106
116
  end
107
117
 
118
+ def ask_protected_fetch
119
+ say_current_config(:protected_fetch, "Protected Fetch enabled")
120
+
121
+ value = @cli.yes? "Use Protected Fetch for Private Gems? [y/N]"
122
+ value = Gemstash::Configuration::DEFAULTS[:protected_fetch] if value.is_a?(String) && value.empty?
123
+ @config[:protected_fetch] = value
124
+ end
125
+
126
+ def ask_timeout
127
+ say_current_config(:fetch_timeout, "Fetch timeout")
128
+ timeout = @cli.ask "How many seconds to wait when fetching a gem? [20]"
129
+ timeout = Gemstash::Configuration::DEFAULTS[:fetch_timeout] if timeout.to_i < 1
130
+ @config[:fetch_timeout] = timeout.to_i
131
+ end
132
+
108
133
  def check_cache
109
- @cli.say "Checking that the cache is available"
110
- with_new_config { gemstash_env.cache_client.alive! }
111
- rescue => e
112
- say_error "Cache error", e
113
- raise Gemstash::CLI::Error.new(@cli, "The cache is not available")
134
+ try("cache") { gemstash_env.cache_client.alive! }
114
135
  end
115
136
 
116
137
  def check_database
117
- @cli.say "Checking that the database is available"
118
- with_new_config { gemstash_env.db.test_connection }
119
- rescue => e
120
- say_error "Database error", e
121
- raise Gemstash::CLI::Error.new(@cli, "The database is not available")
138
+ try("database") { gemstash_env.db.test_connection }
122
139
  end
123
140
 
124
141
  def check_storage
@@ -130,8 +147,10 @@ module Gemstash
130
147
  # we don't want to store metadata just yet
131
148
  metadata_file = gemstash_env.base_file("metadata.yml")
132
149
  break unless File.exist?(metadata_file)
150
+
133
151
  version = Gem::Version.new(YAML.load_file(metadata_file)[:gemstash_version])
134
152
  break if Gem::Requirement.new("<= #{Gemstash::VERSION}").satisfied_by?(Gem::Version.new(version))
153
+
135
154
  raise Gemstash::CLI::Error.new(@cli, "The base path already exists with a newer version of Gemstash")
136
155
  else
137
156
  @cli.say "Creating the file storage path '#{dir}'"
@@ -143,7 +162,7 @@ module Gemstash
143
162
  def store_config
144
163
  config_dir = File.dirname(config_file)
145
164
  FileUtils.mkpath(config_dir) unless Dir.exist?(config_dir)
146
- File.write(config_file, YAML.dump(@config))
165
+ gemstash_env.atomic_write(config_file) {|f| f.write(YAML.dump(@config)) }
147
166
  end
148
167
 
149
168
  def save_metadata
@@ -155,6 +174,7 @@ module Gemstash
155
174
 
156
175
  def say_error(title, error)
157
176
  return unless @cli.options[:debug]
177
+
158
178
  @cli.say @cli.set_color("#{title}: #{error}", :red)
159
179
 
160
180
  error.backtrace.each do |line|
@@ -168,6 +188,14 @@ module Gemstash
168
188
  ensure
169
189
  gemstash_env.reset
170
190
  end
191
+
192
+ def try(thing, &block)
193
+ @cli.say "Checking that the #{thing} is available"
194
+ with_new_config(&block)
195
+ rescue StandardError => e
196
+ say_error "Error checking #{thing}", e
197
+ raise Gemstash::CLI::Error.new(@cli, "The #{thing} is not available")
198
+ end
171
199
  end
172
200
  end
173
201
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "gemstash"
2
4
  require "puma/cli"
3
5
 
@@ -10,6 +12,7 @@ module Gemstash
10
12
  prepare
11
13
  setup_logging
12
14
  store_daemonized
15
+ @cli.say("Starting gemstash!", :green)
13
16
  Puma::CLI.new(args, Gemstash::Logging::StreamLogger.puma_events).run
14
17
  end
15
18
 
@@ -17,7 +20,8 @@ module Gemstash
17
20
 
18
21
  def setup_logging
19
22
  return unless daemonize?
20
- Gemstash::Logging.setup_logger(gemstash_env.base_file("server.log"))
23
+
24
+ Gemstash::Logging.setup_logger(gemstash_env.log_file)
21
25
  end
22
26
 
23
27
  def store_daemonized
@@ -29,7 +33,7 @@ module Gemstash
29
33
  end
30
34
 
31
35
  def puma_config
32
- File.expand_path("../../puma.rb", __FILE__)
36
+ File.expand_path("../puma.rb", __dir__)
33
37
  end
34
38
 
35
39
  def args
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "gemstash"
2
4
  require "puma/control_cli"
3
5
 
@@ -14,7 +16,7 @@ module Gemstash
14
16
  private
15
17
 
16
18
  def args
17
- pidfile_args + %w(status)
19
+ pidfile_args + %w[status]
18
20
  end
19
21
  end
20
22
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "gemstash"
2
4
  require "puma/control_cli"
3
5
 
@@ -9,12 +11,13 @@ module Gemstash
9
11
  def run
10
12
  prepare
11
13
  Puma::ControlCLI.new(args).run
14
+ @cli.say("Gemstash stopped successfully!", :green)
12
15
  end
13
16
 
14
17
  private
15
18
 
16
19
  def args
17
- pidfile_args + %w(stop)
20
+ pidfile_args + %w[stop]
18
21
  end
19
22
  end
20
23
  end
data/lib/gemstash/cli.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "gemstash"
2
4
  require "thor"
3
5
  require "thor/error"
@@ -23,13 +25,40 @@ module Gemstash
23
25
  true
24
26
  end
25
27
 
26
- desc "authorize [PERMISSIONS...]", "Add authorizations to push/yank/unyank private gems"
28
+ def self.start(args = ARGV)
29
+ help_flags = %w[-h --help]
30
+
31
+ if args.any? {|a| help_flags.include?(a) }
32
+ super(%w[help] + args.reject {|a| help_flags.include?(a) })
33
+ else
34
+ super
35
+ end
36
+ end
37
+
38
+ def help(command = nil)
39
+ command ||= "readme"
40
+ page = manpage(command)
41
+
42
+ if page && which("man")
43
+ exec "man", page
44
+ elsif page
45
+ puts File.read("#{page}.txt")
46
+ else
47
+ super
48
+ end
49
+ end
50
+
51
+ desc "authorize [PERMISSIONS...]", "Add authorizations to push/yank private gems"
27
52
  method_option :remove, :type => :boolean, :default => false, :desc =>
28
53
  "Remove an authorization key"
54
+ method_option :list, :type => :boolean, :default => false, :desc =>
55
+ "List existing authorization keys"
29
56
  method_option :config_file, :type => :string, :desc =>
30
57
  "Config file to save to"
31
58
  method_option :key, :type => :string, :desc =>
32
59
  "Authorization key to create/update/delete (optional unless deleting)"
60
+ method_option :name, :type => :string, :desc =>
61
+ "Name of the key (optional)"
33
62
  def authorize(*args)
34
63
  Gemstash::CLI::Authorize.new(self, *args).run
35
64
  end
@@ -67,5 +96,34 @@ module Gemstash
67
96
  def stop
68
97
  Gemstash::CLI::Stop.new(self).run
69
98
  end
99
+
100
+ desc "version", "Prints gemstash version information"
101
+ def version
102
+ say "Gemstash version #{Gemstash::VERSION}"
103
+ end
104
+ map %w[-v --version] => :version
105
+
106
+ private
107
+
108
+ def manpage(command)
109
+ page = File.expand_path("../man/gemstash-#{command}", __FILE__)
110
+ return page if File.file?(page)
111
+
112
+ 1.upto(8) do |section|
113
+ page = File.expand_path("../man/gemstash-#{command}.#{section}", __FILE__)
114
+ return page if File.file?(page)
115
+ end
116
+
117
+ nil
118
+ end
119
+
120
+ def which(executable)
121
+ ENV["PATH"].split(File::PATH_SEPARATOR).each do |path|
122
+ exe_path = File.join(path, executable)
123
+ return exe_path if File.file?(exe_path) && File.executable?(exe_path)
124
+ end
125
+
126
+ nil
127
+ end
70
128
  end
71
129
  end
@@ -1,13 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "gemstash"
2
4
  require "puma/commonlogger"
3
5
 
4
6
  use Rack::Deflater
5
7
  use Gemstash::Logging::RackMiddleware
6
8
 
7
- if Gemstash::Env.daemonized?
8
- use Puma::CommonLogger, Gemstash::Logging::StreamLogger.for_stdout
9
- end
9
+ use Puma::CommonLogger, Gemstash::Logging::StreamLogger.for_stdout if Gemstash::Env.daemonized?
10
10
 
11
11
  use Gemstash::Env::RackMiddleware, Gemstash::Env.current
12
12
  use Gemstash::GemSource::RackMiddleware
13
+ use Gemstash::Health::RackMiddleware
13
14
  run Gemstash::Web.new(gemstash_env: Gemstash::Env.current)
@@ -1,28 +1,50 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "yaml"
4
+ require "erb"
2
5
 
3
6
  module Gemstash
4
- #:nodoc:
7
+ # :nodoc:
5
8
  class Configuration
6
9
  DEFAULTS = {
7
- :cache_type => "memory",
8
- :base_path => File.expand_path("~/.gemstash"),
9
- :db_adapter => "sqlite3",
10
- :bind => "tcp://0.0.0.0:9292",
11
- :rubygems_url => "https://www.rubygems.org"
10
+ cache_type: "memory",
11
+ base_path: File.expand_path("~/.gemstash"),
12
+ db_adapter: "sqlite3",
13
+ bind: "tcp://0.0.0.0:9292",
14
+ rubygems_url: "https://rubygems.org",
15
+ ignore_gemfile_source: false,
16
+ protected_fetch: false,
17
+ fetch_timeout: 20,
18
+ # Actual default for db_connection_options is dynamic based on the adapter
19
+ db_connection_options: {},
20
+ puma_threads: 16,
21
+ puma_workers: 1,
22
+ cache_expiration: 30 * 60,
23
+ cache_max_size: 500
12
24
  }.freeze
13
25
 
14
26
  DEFAULT_FILE = File.expand_path("~/.gemstash/config.yml").freeze
15
27
 
28
+ # This error is thrown when a config file is explicitly specified that
29
+ # doesn't exist.
30
+ class MissingFileError < StandardError
31
+ def initialize(file)
32
+ super("Missing config file: #{file}")
33
+ end
34
+ end
35
+
16
36
  def initialize(file: nil, config: nil)
17
37
  if config
18
38
  @config = DEFAULTS.merge(config).freeze
19
39
  return
20
40
  end
21
41
 
22
- file ||= DEFAULT_FILE
42
+ raise MissingFileError, file if file && !File.exist?(file)
43
+
44
+ file ||= default_file
23
45
 
24
46
  if File.exist?(file)
25
- @config = YAML.load_file(file)
47
+ @config = parse_config(file)
26
48
  @config = DEFAULTS.merge(@config)
27
49
  @config.freeze
28
50
  else
@@ -37,5 +59,36 @@ module Gemstash
37
59
  def [](key)
38
60
  @config[key]
39
61
  end
62
+
63
+ # @return [Hash] Sequel connection configuration hash
64
+ def database_connection_config
65
+ case self[:db_adapter]
66
+ when "sqlite3"
67
+ { max_connections: 1 }.merge(self[:db_connection_options])
68
+ when "postgres", "mysql", "mysql2"
69
+ { max_connections: (self[:puma_workers] * self[:puma_threads]) + 1 }.merge(self[:db_connection_options])
70
+ else
71
+ raise "Unsupported DB adapter: '#{self[:db_adapter]}'"
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def default_file
78
+ # Support the config file being specified via environment variable
79
+ gemstash_config = ENV["GEMSTASH_CONFIG"]
80
+ return gemstash_config if gemstash_config
81
+
82
+ # If no environment variable is used, fall back to the normal defaults
83
+ File.exist?("#{DEFAULT_FILE}.erb") ? "#{DEFAULT_FILE}.erb" : DEFAULT_FILE
84
+ end
85
+
86
+ def parse_config(file)
87
+ if file.end_with?(".erb")
88
+ YAML.load(ERB.new(File.read(file)).result) || {}
89
+ else
90
+ YAML.load_file(file) || {}
91
+ end
92
+ end
40
93
  end
41
94
  end
@@ -1,17 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "gemstash"
2
4
 
3
5
  module Gemstash
4
6
  module DB
5
7
  # Sequel model for authorizations table.
6
8
  class Authorization < Sequel::Model
7
- def self.insert_or_update(auth_key, permissions)
9
+ def self.insert_or_update(auth_key, permissions, name = nil)
8
10
  db.transaction do
9
11
  record = self[auth_key: auth_key]
10
12
 
11
13
  if record
12
- record.update(permissions: permissions)
14
+ record.update(permissions: permissions, name: name)
13
15
  else
14
- create(auth_key: auth_key, permissions: permissions)
16
+ create(auth_key: auth_key, permissions: permissions, name: name)
15
17
  end
16
18
  end
17
19
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "gemstash"
4
+
5
+ module Gemstash
6
+ module DB
7
+ # Sequel model for cached_rubygems table.
8
+ class CachedRubygem < Sequel::Model
9
+ def self.store(upstream, gem_name, resource_type)
10
+ db.transaction do
11
+ upstream_id = Gemstash::DB::Upstream.find_or_insert(upstream)
12
+ record = self[upstream_id: upstream_id, name: gem_name.name, resource_type: resource_type.to_s]
13
+ return record.id if record
14
+
15
+ new(upstream_id: upstream_id, name: gem_name.name, resource_type: resource_type.to_s).tap(&:save).id
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "gemstash"
2
4
 
3
5
  module Gemstash
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "gemstash"
2
4
 
3
5
  module Gemstash
@@ -7,6 +9,7 @@ module Gemstash
7
9
  def self.find_or_insert(spec)
8
10
  record = self[name: spec.name]
9
11
  return record.id if record
12
+
10
13
  new(name: spec.name).tap(&:save).id
11
14
  end
12
15
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gemstash
4
+ module DB
5
+ # Sequel model for upstreams table.
6
+ class Upstream < Sequel::Model
7
+ def self.find_or_insert(upstream)
8
+ record = self[uri: upstream.to_s]
9
+ return record.id if record
10
+
11
+ new(uri: upstream.to_s, host_id: upstream.host_id).tap(&:save).id
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "gemstash"
2
4
 
3
5
  module Gemstash
@@ -19,8 +21,28 @@ module Gemstash
19
21
  [rubygem.name, Gem::Version.new(number), platform]
20
22
  end
21
23
 
22
- def self.for_spec_collection(prerelease: false)
23
- where(indexed: true, prerelease: prerelease).association_join(:rubygem)
24
+ def self.slug(params)
25
+ version = params[:version]
26
+ platform = params[:platform]
27
+
28
+ if platform.to_s.empty?
29
+ version
30
+ else
31
+ "#{version}-#{platform}"
32
+ end
33
+ end
34
+
35
+ def self.for_spec_collection(prerelease: false, latest: false)
36
+ versions = where(indexed: true, prerelease: prerelease).association_join(:rubygem)
37
+ latest ? select_latest(versions) : versions
38
+ end
39
+
40
+ def self.select_latest(versions)
41
+ versions.
42
+ all.
43
+ group_by {|version| [version.rubygem_id, version.platform] }.
44
+ values.
45
+ map {|gem_versions| gem_versions.max_by {|version| Gem::Version.new(version.number) } }
24
46
  end
25
47
 
26
48
  def self.find_by_spec(gem_id, spec)
@@ -32,6 +54,7 @@ module Gemstash
32
54
  def self.find_by_full_name(full_name)
33
55
  result = self[full_name: full_name]
34
56
  return result if result
57
+
35
58
  # Try again with the default platform, in case it is implied
36
59
  self[full_name: "#{full_name}-ruby"]
37
60
  end
data/lib/gemstash/db.rb CHANGED
@@ -1,15 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "gemstash"
2
4
 
3
5
  module Gemstash
4
6
  # Module containing the DB models.
5
7
  module DB
6
8
  raise "Gemstash::DB cannot be loaded until the Gemstash::Env is available" unless Gemstash::Env.available?
9
+
7
10
  Sequel::Model.db = Gemstash::Env.current.db
8
11
  Sequel::Model.raise_on_save_failure = true
9
12
  Sequel::Model.plugin :timestamps, update_on_create: true
10
13
  autoload :Authorization, "gemstash/db/authorization"
14
+ autoload :CachedRubygem, "gemstash/db/cached_rubygem"
11
15
  autoload :Dependency, "gemstash/db/dependency"
12
16
  autoload :Rubygem, "gemstash/db/rubygem"
17
+ autoload :Upstream, "gemstash/db/upstream"
13
18
  autoload :Version, "gemstash/db/version"
14
19
  end
15
20
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "cgi"
2
4
  require "set"
3
5
 
4
6
  module Gemstash
5
- #:nodoc:
7
+ # :nodoc:
6
8
  class Dependencies
7
9
  def self.for_private
8
10
  new(scope: "private", db_model: Gemstash::DB::Dependency)
@@ -22,7 +24,7 @@ module Gemstash
22
24
  Fetcher.new(gems, @scope, @http_client, @db_model).fetch
23
25
  end
24
26
 
25
- #:nodoc:
27
+ # :nodoc:
26
28
  class Fetcher
27
29
  include Gemstash::Env::Helper
28
30
  include Gemstash::Logging
@@ -59,6 +61,7 @@ module Gemstash
59
61
  def fetch_from_database
60
62
  return if done?
61
63
  return unless @db_model
64
+
62
65
  log.info "Querying dependencies: #{@gems.to_a.join(", ")}"
63
66
 
64
67
  @db_model.fetch(@gems) do |gem, value|
@@ -71,6 +74,7 @@ module Gemstash
71
74
  def fetch_from_web
72
75
  return if done?
73
76
  return unless @http_client
77
+
74
78
  log.info "Fetching dependencies: #{@gems.to_a.join(", ")}"
75
79
  gems_param = @gems.map {|gem| CGI.escape(gem) }.join(",")
76
80
  fetched = @http_client.get("api/v1/dependencies?gems=#{gems_param}")