gemstash 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +33 -0
  3. data/lib/gemstash.rb +2 -0
  4. data/lib/gemstash/api_key_authorization.rb +29 -0
  5. data/lib/gemstash/authorization.rb +5 -1
  6. data/lib/gemstash/cli/authorize.rb +1 -1
  7. data/lib/gemstash/cli/setup.rb +50 -37
  8. data/lib/gemstash/cli/start.rb +1 -1
  9. data/lib/gemstash/config.ru +1 -0
  10. data/lib/gemstash/configuration.rb +35 -3
  11. data/lib/gemstash/db/version.rb +11 -0
  12. data/lib/gemstash/env.rb +16 -10
  13. data/lib/gemstash/gem_fetcher.rb +1 -1
  14. data/lib/gemstash/gem_pusher.rb +15 -17
  15. data/lib/gemstash/gem_source/private_source.rb +29 -44
  16. data/lib/gemstash/gem_source/upstream_source.rb +4 -4
  17. data/lib/gemstash/gem_unyanker.rb +10 -4
  18. data/lib/gemstash/gem_yanker.rb +10 -4
  19. data/lib/gemstash/health.rb +53 -0
  20. data/lib/gemstash/http_client.rb +5 -3
  21. data/lib/gemstash/logging.rb +1 -1
  22. data/lib/gemstash/man/gemstash-authorize.1 +6 -5
  23. data/lib/gemstash/man/gemstash-authorize.1.txt +14 -13
  24. data/lib/gemstash/man/gemstash-configuration.5 +90 -8
  25. data/lib/gemstash/man/gemstash-configuration.5.txt +82 -6
  26. data/lib/gemstash/man/gemstash-customize.7 +68 -12
  27. data/lib/gemstash/man/gemstash-customize.7.txt +64 -26
  28. data/lib/gemstash/man/gemstash-debugging.7 +1 -1
  29. data/lib/gemstash/man/gemstash-deploy.7 +33 -1
  30. data/lib/gemstash/man/gemstash-deploy.7.txt +25 -0
  31. data/lib/gemstash/man/gemstash-mirror.7 +1 -1
  32. data/lib/gemstash/man/gemstash-multiple-sources.7 +1 -1
  33. data/lib/gemstash/man/gemstash-private-gems.7 +52 -3
  34. data/lib/gemstash/man/gemstash-private-gems.7.txt +39 -4
  35. data/lib/gemstash/man/gemstash-readme.7 +34 -4
  36. data/lib/gemstash/man/gemstash-readme.7.txt +34 -12
  37. data/lib/gemstash/man/gemstash-setup.1 +3 -1
  38. data/lib/gemstash/man/gemstash-setup.1.txt +3 -1
  39. data/lib/gemstash/man/gemstash-start.1 +4 -3
  40. data/lib/gemstash/man/gemstash-start.1.txt +5 -4
  41. data/lib/gemstash/man/gemstash-status.1 +4 -3
  42. data/lib/gemstash/man/gemstash-status.1.txt +3 -2
  43. data/lib/gemstash/man/gemstash-stop.1 +4 -3
  44. data/lib/gemstash/man/gemstash-stop.1.txt +3 -2
  45. data/lib/gemstash/man/gemstash-version.1 +1 -1
  46. data/lib/gemstash/puma.rb +2 -2
  47. data/lib/gemstash/specs_builder.rb +14 -16
  48. data/lib/gemstash/version.rb +1 -1
  49. metadata +29 -7
@@ -6,6 +6,7 @@ module Gemstash
6
6
  class PrivateSource < Gemstash::GemSource::Base
7
7
  include Gemstash::GemSource::DependencyCaching
8
8
  include Gemstash::Env::Helper
9
+ attr_accessor :auth
9
10
 
10
11
  def self.rack_env_rewriter
11
12
  @rack_env_rewriter ||= Gemstash::RackEnvRewriter.new(%r{\A/private})
@@ -23,27 +24,15 @@ module Gemstash
23
24
  end
24
25
 
25
26
  def serve_add_gem
26
- authenticated("Gemstash Private Gems") do
27
- auth = request.env["HTTP_AUTHORIZATION"]
28
- gem = request.body.read
29
- Gemstash::GemPusher.new(auth, gem).push
30
- end
27
+ protected(Gemstash::GemPusher)
31
28
  end
32
29
 
33
30
  def serve_yank
34
- authenticated("Gemstash Private Gems") do
35
- auth = request.env["HTTP_AUTHORIZATION"]
36
- gem_name = params[:gem_name]
37
- Gemstash::GemYanker.new(auth, gem_name, slug_param).yank
38
- end
31
+ protected(Gemstash::GemYanker)
39
32
  end
40
33
 
41
34
  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
35
+ protected(Gemstash::GemUnyanker)
47
36
  end
48
37
 
49
38
  def serve_add_spec_json
@@ -67,11 +56,14 @@ module Gemstash
67
56
  end
68
57
 
69
58
  def serve_marshal(id)
70
- gem_full_name = id.sub(/\.gemspec\.rz\z/, "")
71
- gem = fetch_gem(gem_full_name)
72
- halt 404 unless gem.exist?(:spec)
73
- content_type "application/octet-stream"
74
- gem.content(:spec)
59
+ authorization.protect(self) do
60
+ auth.check("fetch") if gemstash_env.config[:protected_fetch]
61
+ gem_full_name = id.sub(/\.gemspec\.rz\z/, "")
62
+ gem = fetch_gem(gem_full_name)
63
+ halt 404 unless gem.exist?(:spec)
64
+ content_type "application/octet-stream"
65
+ gem.content(:spec)
66
+ end
75
67
  end
76
68
 
77
69
  def serve_actual_gem(id)
@@ -79,45 +71,38 @@ module Gemstash
79
71
  end
80
72
 
81
73
  def serve_gem(id)
82
- gem_full_name = id.sub(/\.gem\z/, "")
83
- gem = fetch_gem(gem_full_name)
84
- content_type "application/octet-stream"
85
- gem.content(:gem)
74
+ authorization.protect(self) do
75
+ auth.check("fetch") if gemstash_env.config[:protected_fetch]
76
+ gem_full_name = id.sub(/\.gem\z/, "")
77
+ gem = fetch_gem(gem_full_name)
78
+ content_type "application/octet-stream"
79
+ gem.content(:gem)
80
+ end
86
81
  end
87
82
 
88
83
  def serve_specs
89
- content_type "application/octet-stream"
90
- Gemstash::SpecsBuilder.all
84
+ params[:prerelease] = false
85
+ protected(Gemstash::SpecsBuilder)
91
86
  end
92
87
 
93
88
  def serve_latest_specs
94
- content_type "application/octet-stream"
95
- Gemstash::SpecsBuilder.latest
89
+ params[:latest] = true
90
+ protected(Gemstash::SpecsBuilder)
96
91
  end
97
92
 
98
93
  def serve_prerelease_specs
99
- content_type "application/octet-stream"
100
- Gemstash::SpecsBuilder.prerelease
94
+ params[:prerelease] = true
95
+ protected(Gemstash::SpecsBuilder)
101
96
  end
102
97
 
103
98
  private
104
99
 
105
- def slug_param
106
- version = params[:version]
107
- platform = params[:platform]
108
-
109
- if platform.to_s.empty?
110
- version
111
- else
112
- "#{version}-#{platform}"
113
- end
100
+ def protected(servable)
101
+ authorization.protect(self) { servable.serve(self) }
114
102
  end
115
103
 
116
- def authenticated(realm)
117
- yield
118
- rescue Gemstash::NotAuthorizedError => e
119
- headers["WWW-Authenticate"] = "Basic realm=\"#{realm}\""
120
- halt 401, e.message
104
+ def authorization
105
+ Gemstash::ApiKeyAuthorization
121
106
  end
122
107
 
123
108
  def dependencies
@@ -196,13 +196,13 @@ module Gemstash
196
196
  # default upstream).
197
197
  class RubygemsSource < Gemstash::GemSource::UpstreamSource
198
198
  def self.matches?(env)
199
- if env["HTTP_X_GEMFILE_SOURCE"].to_s.empty?
200
- env["gemstash.upstream"] = env["gemstash.env"].config[:rubygems_url]
199
+ env["gemstash.upstream"] = if env["HTTP_X_GEMFILE_SOURCE"].to_s.empty?
200
+ env["gemstash.env"].config[:rubygems_url]
201
201
  else
202
- env["gemstash.upstream"] = env["HTTP_X_GEMFILE_SOURCE"]
202
+ env["HTTP_X_GEMFILE_SOURCE"]
203
203
  end
204
- capture_user_agent(env)
205
204
 
205
+ capture_user_agent(env)
206
206
  true
207
207
  end
208
208
  end
@@ -17,13 +17,19 @@ module Gemstash
17
17
  class NotYankedVersionError < StandardError
18
18
  end
19
19
 
20
- def initialize(auth_key, gem_name, slug)
21
- @auth_key = auth_key
20
+ def self.serve(app)
21
+ gem_name = app.params[:gem_name]
22
+ slug = Gemstash::DB::Version.slug(app.params)
23
+ new(app.auth, gem_name, slug).serve
24
+ end
25
+
26
+ def initialize(auth, gem_name, slug)
27
+ @auth = auth
22
28
  @gem_name = gem_name
23
29
  @slug = slug
24
30
  end
25
31
 
26
- def unyank
32
+ def serve
27
33
  check_auth
28
34
  update_database
29
35
  invalidate_cache
@@ -40,7 +46,7 @@ module Gemstash
40
46
  end
41
47
 
42
48
  def check_auth
43
- Gemstash::Authorization.check(@auth_key, "unyank")
49
+ @auth.check("unyank")
44
50
  end
45
51
 
46
52
  def update_database
@@ -17,13 +17,19 @@ module Gemstash
17
17
  class YankedVersionError < StandardError
18
18
  end
19
19
 
20
- def initialize(auth_key, gem_name, slug)
21
- @auth_key = auth_key
20
+ def self.serve(app)
21
+ gem_name = app.params[:gem_name]
22
+ slug = Gemstash::DB::Version.slug(app.params)
23
+ new(app.auth, gem_name, slug).serve
24
+ end
25
+
26
+ def initialize(auth, gem_name, slug)
27
+ @auth = auth
22
28
  @gem_name = gem_name
23
29
  @slug = slug
24
30
  end
25
31
 
26
- def yank
32
+ def serve
27
33
  check_auth
28
34
  update_database
29
35
  invalidate_cache
@@ -40,7 +46,7 @@ module Gemstash
40
46
  end
41
47
 
42
48
  def check_auth
43
- Gemstash::Authorization.check(@auth_key, "yank")
49
+ @auth.check("yank")
44
50
  end
45
51
 
46
52
  def update_database
@@ -0,0 +1,53 @@
1
+ require "gemstash"
2
+ require "date"
3
+ require "server_health_check_rack"
4
+ require "sequel"
5
+
6
+ module Gemstash
7
+ # This module contains the logic used to supply a health monitor for
8
+ # Gemstash. You can access the health monitor at the /health endpoint.
9
+ module Health
10
+ # This check can be used if you don't want to read or write content during a
11
+ # health check.
12
+ def self.heartbeat
13
+ true
14
+ end
15
+
16
+ def self.check_storage_read
17
+ if check_storage_write
18
+ content = Gemstash::Storage.for("health").resource("test").content(:example)
19
+ content =~ /\Acontent-\d+\z/
20
+ end
21
+ end
22
+
23
+ def self.check_storage_write
24
+ resource = Gemstash::Storage.for("health").resource("test")
25
+ resource.save(example: "content-#{Time.now.to_i}")
26
+ true
27
+ end
28
+
29
+ def self.check_db_read
30
+ result = Gemstash::Env.current.db[:rubygems].where(name: "testing_db_read").count
31
+ result.is_a?(Numeric)
32
+ end
33
+
34
+ def self.check_db_write
35
+ Gemstash::Env.current.db.transaction do
36
+ Gemstash::Env.current.db[:rubygems].insert(name: "health_check:fake_gem_name",
37
+ created_at: DateTime.now,
38
+ updated_at: DateTime.now)
39
+ # We don't want to actually write to the database
40
+ raise Sequel::Rollback
41
+ end
42
+
43
+ true
44
+ end
45
+
46
+ ServerHealthCheckRack::Checks.check("heartbeat") { Gemstash::Health.heartbeat }
47
+ ServerHealthCheckRack::Checks.check("storage_read") { Gemstash::Health.check_storage_read }
48
+ ServerHealthCheckRack::Checks.check("storage_write") { Gemstash::Health.check_storage_write }
49
+ ServerHealthCheckRack::Checks.check("db_read") { Gemstash::Health.check_db_read }
50
+ ServerHealthCheckRack::Checks.check("db_write") { Gemstash::Health.check_db_write }
51
+ RackMiddleware = ServerHealthCheckRack::Middleware
52
+ end
53
+ end
@@ -22,14 +22,16 @@ module Gemstash
22
22
 
23
23
  #:nodoc:
24
24
  class HTTPClient
25
+ extend Gemstash::Env::Helper
25
26
  include Gemstash::Logging
26
27
 
27
- DEFAULT_USER_AGENT = "Gemstash/#{Gemstash::VERSION}"
28
+ DEFAULT_USER_AGENT = "Gemstash/#{Gemstash::VERSION}".freeze
28
29
 
29
30
  def self.for(upstream)
30
31
  client = Faraday.new(upstream.to_s) do |config|
31
32
  config.use FaradayMiddleware::FollowRedirects
32
33
  config.adapter :net_http
34
+ config.options.timeout = gemstash_env.config[:fetch_timeout]
33
35
  end
34
36
  user_agent = "#{upstream.user_agent} " unless upstream.user_agent.to_s.empty?
35
37
  user_agent = user_agent.to_s + DEFAULT_USER_AGENT
@@ -61,11 +63,11 @@ module Gemstash
61
63
 
62
64
  private
63
65
 
64
- def with_retries(times: 3, &block)
66
+ def with_retries(times: 3)
65
67
  loop do
66
68
  times -= 1
67
69
  begin
68
- return block.call
70
+ return yield
69
71
  rescue Faraday::ConnectionFailed => e
70
72
  log_error("Connection failure", e)
71
73
  raise(ConnectionError, e.message) unless times > 0
@@ -10,7 +10,7 @@ module Gemstash
10
10
  warn: Logger::WARN,
11
11
  error: Logger::ERROR,
12
12
  fatal: Logger::FATAL
13
- }
13
+ }.freeze
14
14
 
15
15
  def log
16
16
  Gemstash::Logging.logger
@@ -1,4 +1,4 @@
1
- .\" Automatically generated by Pandoc 1.16.0.2
1
+ .\" Automatically generated by Pandoc 1.19.2.1
2
2
  .\"
3
3
  .TH "gemstash\-authorize" "1" "October 9, 2015" "" ""
4
4
  .hy
@@ -14,8 +14,8 @@ privately stored gems
14
14
  Adds or removes authorization to interact with privately stored gems.
15
15
  .PP
16
16
  Any arguments will be used as specific permissions.
17
- Valid permissions include \f[C]push\f[], \f[C]yank\f[], and
18
- \f[C]unyank\f[].
17
+ Valid permissions include \f[C]push\f[], \f[C]yank\f[], \f[C]unyank\f[],
18
+ and \f[C]fetch\f[].
19
19
  If no permissions are provided, then all permissions will be granted
20
20
  (including any that may be added in future versions of Gemstash).
21
21
  .SS USAGE
@@ -32,8 +32,9 @@ gemstash\ authorize\ \-\-remove\ \-\-key\ <secure\-key>
32
32
  .IP \[bu] 2
33
33
  \f[C]\-\-config\-file\ FILE\f[]: Specify the config file to use.
34
34
  If you aren\[aq]t using the default config file at
35
- \f[C]~/.gemstash/config.yml\f[], then you must specify the config file
36
- via this option.
35
+ \f[C]~/.gemstash/config.yml\f[] or
36
+ \f[C]~/.gemstash/config.yml.erb\f[] (gemstash help customize.7), then
37
+ you must specify the config file via this option.
37
38
  .IP \[bu] 2
38
39
  \f[C]\-\-key\ SECURE_KEY\f[]: Specify the API key to affect.
39
40
  This should be the actual key value, not a name.
@@ -14,9 +14,9 @@ DESCRIPTION
14
14
  Adds or removes authorization to interact with privately stored gems.
15
15
 
16
16
  Any arguments will be used as specific permissions. Valid permissions
17
- include push, yank, and unyank. If no permissions are provided, then
18
- all permissions will be granted (including any that may be added in fu-
19
- ture versions of Gemstash).
17
+ include push, yank, unyank, and fetch. If no permissions are provided,
18
+ then all permissions will be granted (including any that may be added
19
+ in future versions of Gemstash).
20
20
 
21
21
  USAGE
22
22
  gemstash authorize
@@ -26,18 +26,19 @@ DESCRIPTION
26
26
 
27
27
  OPTIONS
28
28
  o --config-file FILE: Specify the config file to use. If you aren't
29
- using the default config file at ~/.gemstash/config.yml, then you
30
- must specify the config file via this option.
31
-
32
- o --key SECURE_KEY: Specify the API key to affect. This should be the
33
- actual key value, not a name. This option is required when using
34
- --remove but is optional otherwise. If adding an authorization, us-
35
- ing this will either create or update the permissions for the speci-
36
- fied API key. If missing, a new API key will always be generated.
29
+ using the default config file at ~/.gemstash/config.yml or ~/.gem-
30
+ stash/config.yml.erb (gemstash help customize.7), then you must spec-
31
+ ify the config file via this option.
32
+
33
+ o --key SECURE_KEY: Specify the API key to affect. This should be the
34
+ actual key value, not a name. This option is required when using
35
+ --remove but is optional otherwise. If adding an authorization, us-
36
+ ing this will either create or update the permissions for the speci-
37
+ fied API key. If missing, a new API key will always be generated.
37
38
  Note that a key can only have a maximum length of 255 chars.
38
39
 
39
- o --remove: Remove an authorization rather than add or update one.
40
- When removing, permission values are not allowed. The --key <se-
40
+ o --remove: Remove an authorization rather than add or update one.
41
+ When removing, permission values are not allowed. The --key <se-
41
42
  cure-key> option is required.
42
43
 
43
44
 
@@ -1,4 +1,4 @@
1
- .\" Automatically generated by Pandoc 1.16.0.2
1
+ .\" Automatically generated by Pandoc 1.19.2.1
2
2
  .\"
3
3
  .TH "gemstash\-configuration" "5" "October 13, 2015" "" ""
4
4
  .hy
@@ -16,8 +16,15 @@ gemstash\-configuration
16
16
  :memcached_servers:\ localhost:11211
17
17
  :db_adapter:\ postgres
18
18
  :db_url:\ postgres:///gemstash
19
+ :db_connection_options:
20
+ \ \ :test:\ true
21
+ \ \ :pool_timeout:\ 2
19
22
  :rubygems_url:\ https://my.gem\-source.local
23
+ :puma_threads:\ 32
20
24
  :bind:\ tcp://0.0.0.0:4242
25
+ :protected_fetch:\ true
26
+ :fetch_timeout:\ 10
27
+ :log_file:\ gemstash.log
21
28
  \f[]
22
29
  .fi
23
30
  .SH BASE PATH
@@ -77,28 +84,48 @@ When \f[C]sqlite3\f[] is used, the database will be located at
77
84
  \f[C]gemstash.db\f[] within the directory specified by
78
85
  \f[C]:base_path\f[].
79
86
  The database will automatically be created when using \f[C]sqlite3\f[].
80
- When \f[C]postgres\f[] is used, the database to connect to must be
81
- specified in the \f[C]:db_url\f[] configuration key.
82
- The database must already be created when using \f[C]postgres\f[].
87
+ When \f[C]postgres\f[], \f[C]mysql\f[], or \f[C]mysql2\f[] is used, the
88
+ database to connect to must be specified in the \f[C]:db_url\f[]
89
+ configuration key.
90
+ The database must already be created when using anything other than
91
+ \f[C]sqlite3\f[].
83
92
  .SS DEFAULT VALUE
84
93
  .PP
85
94
  \f[C]sqlite3\f[]
86
95
  .SS VALID VALUES
87
96
  .PP
88
- \f[C]sqlite3\f[], \f[C]postgres\f[]
97
+ \f[C]sqlite3\f[], \f[C]postgres\f[], \f[C]mysql\f[], \f[C]mysql2\f[]
89
98
  .SH DB URL
90
99
  .PP
91
100
  \f[C]:db_url\f[]
92
101
  .PP
93
- Specifies the database to connect to when using \f[C]postgres\f[] for
94
- the \f[C]:db_adapter\f[].
95
- Only used when \f[C]postgres\f[] is used for \f[C]:db_adapter\f[].
102
+ Specifies the database to connect to when using \f[C]postgres\f[],
103
+ \f[C]mysql\f[], or \f[C]mysql2\f[] for the \f[C]:db_adapter\f[].
104
+ Only used when the \f[C]:db_adapter\f[] is not \f[C]sqlite3\f[].
96
105
  .SS DEFAULT VALUE
97
106
  .PP
98
107
  None
99
108
  .SS VALID VALUES
100
109
  .PP
101
110
  A valid database URL for the Sequel gem (http://sequel.jeremyevans.net/)
111
+ .SH DB CONNECTION OPTIONS
112
+ .PP
113
+ \f[C]:db_connection_options\f[]
114
+ .PP
115
+ Specifies additional \f[C]Sequel.connect\f[] options to use.
116
+ Note that any options here are merged in with the default options, so
117
+ you need not specify the \f[C]max_connections\f[] if you customize this
118
+ option.
119
+ .SS DEFAULT VALUE
120
+ .PP
121
+ \f[C]{\ max_connections:\ 1\ }\f[] for \f[C]sqlite3\f[] adapter,
122
+ \f[C]{\ max_connections:\ config[:puma_threads]\ +\ 1\ }\f[] for any
123
+ other adapter.
124
+ .SS VALID VALUES
125
+ .PP
126
+ A valid connection options Hash for the
127
+ Sequel.connect (http://sequel.jeremyevans.net/rdoc/files/doc/opening_databases_rdoc.html#label-General+connection+options)
128
+ method.
102
129
  .SH RUBYGEMS URL
103
130
  .PP
104
131
  \f[C]:rubygems_url\f[]
@@ -115,6 +142,17 @@ for the previous value.
115
142
  .SS VALID VALUES
116
143
  .PP
117
144
  A valid gem source URL
145
+ .SH PUMA THREADS
146
+ .PP
147
+ \f[C]:puma_threads\f[]
148
+ .PP
149
+ Specifies the number of threads used for the Gemstash server.
150
+ .SS DEFAULT VALUE
151
+ .PP
152
+ \f[C]16\f[]
153
+ .SS VALID VALUES
154
+ .PP
155
+ Integer value with a minimum of \f[C]1\f[]
118
156
  .SH BIND ADDRESS
119
157
  .PP
120
158
  \f[C]:bind\f[]
@@ -131,3 +169,47 @@ as the root user.
131
169
  .PP
132
170
  Any valid binding that is supported by
133
171
  Puma (https://github.com/puma/puma#binding-tcp--sockets)
172
+ .SH PROTECTED FETCH
173
+ .PP
174
+ \f[C]:protected_fetch\f[]
175
+ .PP
176
+ Tells Gemstash to authenticate via an API key before allowing the
177
+ fetching of private gems and specs.
178
+ The default behavior is to allow unauthenticated download of private
179
+ gems and specs.
180
+ .SS DEFAULT VALUE
181
+ .PP
182
+ \f[C]false\f[]
183
+ .SS VALID VALUES
184
+ .PP
185
+ Boolean values \f[C]true\f[] or \f[C]false\f[]
186
+ .SH FETCH TIMEOUT
187
+ .PP
188
+ \f[C]:fetch_timeout\f[]
189
+ .PP
190
+ The timeout setting for fetching gems.
191
+ Fetching gems over a slow connection may cause timeout errors.
192
+ If you experience timeout errors, you may want to increase this value.
193
+ The default is \f[C]20\f[] seconds.
194
+ .SS DEFAULT VALUE
195
+ .PP
196
+ \f[C]20\f[]
197
+ .SS VALID VALUES
198
+ .PP
199
+ Integer value with a minimum of \f[C]1\f[]
200
+ .SH LOG FILE
201
+ .PP
202
+ \f[C]:log_file\f[]
203
+ .PP
204
+ Indicates the name of the file to use for logging.
205
+ The file will be placed in the base
206
+ path (gemstash help configuration.5).
207
+ .SS DEFAULT VALUE
208
+ .PP
209
+ \f[C]server.log\f[]
210
+ .SS VALID VALUES
211
+ .PP
212
+ Any valid file name, or \f[C]:stdout\f[] to log to \f[C]$stdout\f[]
213
+ .PP
214
+ \f[I]Note: Using \f[C]:stdout\f[] for the \f[C]:log_file\f[] requires
215
+ running with \f[C]\-\-no\-daemonize\f[] (gemstash help start.1).\f[]