boxen-linux 2.7.1

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 (70) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.travis.yml +7 -0
  4. data/Gemfile +2 -0
  5. data/LICENSE +20 -0
  6. data/README.md +50 -0
  7. data/boxen.gemspec +26 -0
  8. data/lib/boxen/check.rb +72 -0
  9. data/lib/boxen/checkout.rb +25 -0
  10. data/lib/boxen/cli.rb +63 -0
  11. data/lib/boxen/config.rb +330 -0
  12. data/lib/boxen/error.rb +4 -0
  13. data/lib/boxen/flags.rb +272 -0
  14. data/lib/boxen/hook.rb +47 -0
  15. data/lib/boxen/hook/github_issue.rb +120 -0
  16. data/lib/boxen/hook/web.rb +56 -0
  17. data/lib/boxen/keychain.rb +63 -0
  18. data/lib/boxen/postflight.rb +13 -0
  19. data/lib/boxen/postflight/active.rb +16 -0
  20. data/lib/boxen/postflight/env.rb +34 -0
  21. data/lib/boxen/preflight.rb +13 -0
  22. data/lib/boxen/preflight/creds.rb +108 -0
  23. data/lib/boxen/preflight/directories.rb +32 -0
  24. data/lib/boxen/preflight/etc_my_cnf.rb +12 -0
  25. data/lib/boxen/preflight/homebrew.rb +13 -0
  26. data/lib/boxen/preflight/identity.rb +16 -0
  27. data/lib/boxen/preflight/os.rb +33 -0
  28. data/lib/boxen/preflight/rbenv.rb +12 -0
  29. data/lib/boxen/preflight/rvm.rb +12 -0
  30. data/lib/boxen/project.rb +20 -0
  31. data/lib/boxen/puppeteer.rb +122 -0
  32. data/lib/boxen/runner.rb +149 -0
  33. data/lib/boxen/service.rb +58 -0
  34. data/lib/boxen/util.rb +17 -0
  35. data/lib/facter/boxen.rb +34 -0
  36. data/lib/system_timer.rb +13 -0
  37. data/script/Boxen +0 -0
  38. data/script/Boxen-linux +0 -0
  39. data/script/bootstrap +7 -0
  40. data/script/build-keychain-helper +6 -0
  41. data/script/build-keyring-helper +9 -0
  42. data/script/release +38 -0
  43. data/script/tests +10 -0
  44. data/src/keychain-helper.c +85 -0
  45. data/src/keyring-helper.c +86 -0
  46. data/test/boxen/test.rb +7 -0
  47. data/test/boxen_check_test.rb +55 -0
  48. data/test/boxen_checkout_test.rb +42 -0
  49. data/test/boxen_cli_test.rb +39 -0
  50. data/test/boxen_config_test.rb +393 -0
  51. data/test/boxen_directories_test.rb +40 -0
  52. data/test/boxen_flags_test.rb +217 -0
  53. data/test/boxen_hook_github_issue_test.rb +294 -0
  54. data/test/boxen_hook_web_test.rb +58 -0
  55. data/test/boxen_keychain_test.rb +24 -0
  56. data/test/boxen_postflight_active_test.rb +29 -0
  57. data/test/boxen_postflight_env_test.rb +6 -0
  58. data/test/boxen_preflight_creds_test.rb +80 -0
  59. data/test/boxen_preflight_etc_my_cnf_test.rb +10 -0
  60. data/test/boxen_preflight_homebrew_test.rb +10 -0
  61. data/test/boxen_preflight_rvm_test.rb +10 -0
  62. data/test/boxen_project_test.rb +14 -0
  63. data/test/boxen_puppeteer_test.rb +101 -0
  64. data/test/boxen_runner_test.rb +171 -0
  65. data/test/boxen_service_test.rb +39 -0
  66. data/test/boxen_util_test.rb +21 -0
  67. data/test/fixtures/repo/modules/projects/manifests/first-project.pp +0 -0
  68. data/test/fixtures/repo/modules/projects/manifests/second-project.pp +0 -0
  69. data/test/system_timer.rb +10 -0
  70. metadata +279 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f2e73551ff475685984522ce2d276c4cb9e231ea
4
+ data.tar.gz: c5e732a6fa14e33fc1235aee463a9cdee3c18f18
5
+ SHA512:
6
+ metadata.gz: eebe4a397ba776c4121d51ed30191783d06c212eb9261eca472e7959999af677bcc529e353ddbc7a714cdf1ee0105d1f7e21a51fdfdb6129b349dc1a0795df9c
7
+ data.tar.gz: 51a0e5b06a075165eaf5735210e23581ea6fc5e65288a7e7153f2d7700eecf630a067f40c831242079471721f2eb5bee147d9fbf4b75259d6acb770c4348eeab
@@ -0,0 +1,11 @@
1
+ /.bundle
2
+ /.env.local.rb
3
+ /.projects
4
+ /.rbenv-version
5
+ /Gemfile.lock
6
+ /bin
7
+ /boxen-*.gem
8
+ /log
9
+ /puppet
10
+ /script/Boxen.dSYM
11
+ /.ruby-version
@@ -0,0 +1,7 @@
1
+ ---
2
+ before_install: gem update --system 2.1.11
3
+ script: "./script/tests"
4
+ gemfile: "this/does/not/exist"
5
+ rvm:
6
+ - "1.8.7"
7
+ - "2.0.0"
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 GitHub, Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,50 @@
1
+ # Boxen [![Build Status](https://travis-ci.org/boxen/boxen.png?branch=master)](https://travis-ci.org/boxen/boxen)
2
+
3
+ Manage Mac development boxes with love (and Puppet).
4
+
5
+ ## Rules for Services
6
+
7
+ 0. Run on a nonstandard port, usually default port + 1000 or 10000.
8
+
9
+ 0. Install with a custom Boxen homebrew formula.
10
+
11
+ 0. Suffix the Homebrew package's version, starting with `-boxen1`.
12
+
13
+ 0. Run as a launchd service in the `dev` namespace, e.g.,
14
+ `dev.dnsmasq`.
15
+
16
+ 0. Store config, data, and log files in
17
+ `$BOXEN_HOME/{config,data,log}`. This will normally require
18
+ customization of a service's Homebrew formula.
19
+
20
+ Sometimes it's not possible to follow these rules, but try hard.
21
+
22
+ ## Projects from the CLI
23
+
24
+ We use a totally awful hack to do from-the-cli project installs of projects.
25
+ We create a file in "$BOXEN_HOME/repodir" called .projects, with a single line.
26
+ That line is made up of projects separated by commas.
27
+ We then read that into a Puppet fact in Puppet-land, and that checks for
28
+ classes that match those project names, and includes them in the catalog.
29
+
30
+ We can't pass a `FACTER_` env var because sudo has `env_reset`
31
+ and we can't just modify the sudoers file due to a chicken-egg problem.
32
+
33
+ ## Hooks
34
+
35
+ 0. All hooks must be in the namespace `Boxen::Hook::MyThing`.
36
+
37
+ 0. All hooks must subclass from `Boxen::Hook`
38
+
39
+ 0. All hooks must provide a private instance method `required_environment_variables` that returns an array with at least one entry.
40
+
41
+ 0. All hooks must provide a private instance method `#call`.
42
+
43
+ ## Contributing
44
+
45
+ Use the OS X system Ruby (1.8.7 or 2.0.0). Run `script/tests` often. Open PR's.
46
+ Use the CI.
47
+
48
+ ## Halp!
49
+
50
+ Use Issues or #boxen on irc.freenode.net.
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "boxen-linux"
5
+ gem.version = "2.7.1"
6
+ gem.authors = ["John Barnette", "Will Farrington", "David Goodlad", "Max Klein"]
7
+ gem.email = ["jbarnette@github.com", "wfarr@github.com", "dgoodlad@github.com", "mklein@jhu.edu"]
8
+ gem.description = "Manage Mac and Linux development boxes with love (and Puppet)."
9
+ gem.summary = "You know, for laptops and stuff."
10
+ gem.homepage = "https://github.com/boxen/boxen"
11
+
12
+ gem.files = `git ls-files`.split $/
13
+ gem.test_files = gem.files.grep /^test/
14
+ gem.require_paths = ["lib"]
15
+
16
+ gem.add_dependency "ansi", "~> 1.4"
17
+ gem.add_dependency "hiera", "~> 1.0"
18
+ gem.add_dependency "highline", "~> 1.6"
19
+ gem.add_dependency "json_pure", [">= 1.7.7", "< 2.0"]
20
+ gem.add_dependency "librarian-puppet", "~> 1.0.0"
21
+ gem.add_dependency "octokit", "~> 2.7", ">= 2.7.1"
22
+ gem.add_dependency "puppet", "~> 3.0"
23
+
24
+ gem.add_development_dependency "minitest", "4.4.0" # pinned for mocha
25
+ gem.add_development_dependency "mocha", "~> 0.13"
26
+ end
@@ -0,0 +1,72 @@
1
+ require "ansi"
2
+
3
+ module Boxen
4
+
5
+ # The superclass for preflight and postflight sanity checks.
6
+
7
+ class Check
8
+
9
+ # A collection of preflight instances for `config`. An instance is
10
+ # created for every constant under `self` that's also a
11
+ # subclass of `self`.
12
+
13
+ def self.checks(config)
14
+ constants.map { |n| const_get n }.
15
+ select { |c| c < self }.
16
+ map { |c| c.new config }
17
+ end
18
+
19
+ # Search `dir` and load all Ruby files under it.
20
+
21
+ def self.register(dir)
22
+ Dir["#{dir}/*.rb"].sort.each { |f| load f }
23
+ end
24
+
25
+ # Check each instance against `config`.
26
+
27
+ def self.run(config)
28
+ checks(config).each { |check| check.run unless check.ok? }
29
+ end
30
+
31
+ attr_reader :config
32
+
33
+ def initialize(config)
34
+ @config = config
35
+ end
36
+
37
+ # Is everything good to go? Implemented by subclasses.
38
+
39
+ def ok?
40
+ raise "Subclasses must implement this method."
41
+ end
42
+
43
+ # Warn, fix, or abort. Implemented by subclasses.
44
+
45
+ def run
46
+ raise "Subclasses must implement this method."
47
+ end
48
+
49
+ # A fancier `abort` and `warn`. This will probably really annoy
50
+ # someone at some point because it's overriding a Kernel method,
51
+ # but it's limited to checks.
52
+
53
+ def abort(message, *extras)
54
+ extras << { :color => :red }
55
+ warn message, *extras
56
+ exit 1
57
+ end
58
+
59
+ def warn(message, *extras)
60
+ options = Hash === extras.last ? extras.pop : {}
61
+ color = options[:color] || :yellow
62
+
63
+ $stderr.puts ANSI.send(color) { "--> #{message}" }
64
+
65
+ unless extras.empty?
66
+ extras.each { |line| $stderr.puts " #{line}" }
67
+ end
68
+
69
+ $stderr.puts
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,25 @@
1
+ module Boxen
2
+ class Checkout
3
+ attr_reader :config
4
+
5
+ def initialize(config)
6
+ @config = config
7
+ end
8
+
9
+ def sha
10
+ Dir.chdir(config.repodir) { `git rev-parse HEAD`.strip }
11
+ end
12
+
13
+ def master?
14
+ Dir.chdir(config.repodir) { `git symbolic-ref HEAD`.strip == 'refs/heads/master' }
15
+ end
16
+
17
+ def dirty?
18
+ !changes.empty?
19
+ end
20
+
21
+ def changes
22
+ Dir.chdir(config.repodir) { `git status --porcelain`.strip }
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,63 @@
1
+ require "boxen/config"
2
+ require "boxen/flags"
3
+ require "boxen/postflight"
4
+ require "boxen/preflight"
5
+ require "boxen/runner"
6
+ require "boxen/util"
7
+
8
+ module Boxen
9
+ class CLI
10
+ attr_reader :config
11
+ attr_reader :flags
12
+ attr_reader :runner
13
+
14
+ def initialize(config, flags)
15
+ @config = config
16
+ @flags = flags
17
+ @runner = Boxen::Runner.new(@config, @flags)
18
+ end
19
+
20
+ def run
21
+ if flags.help?
22
+ puts flags
23
+ exit
24
+ end
25
+
26
+ runner.run
27
+ end
28
+
29
+ # Run Boxen by wiring together the command-line flags, config,
30
+ # preflights, Puppet execution, and postflights. Returns Puppet's
31
+ # exit code.
32
+
33
+ def self.run(*args)
34
+ config = Boxen::Config.load
35
+ flags = Boxen::Flags.new args
36
+
37
+ # Apply command-line flags to the config in case we're changing or
38
+ # overriding anything.
39
+
40
+ flags.apply config
41
+
42
+ # Run the preflight checks.
43
+
44
+ Boxen::Preflight.run config
45
+
46
+ # Save the config for Puppet (and next time).
47
+
48
+ Boxen::Config.save config
49
+
50
+ # Make the magic happen.
51
+
52
+ status = Boxen::CLI.new(config, flags).run
53
+
54
+ # Run the postflight checks.
55
+
56
+ Boxen::Postflight.run config if status.success?
57
+
58
+ # Return Puppet's exit status.
59
+
60
+ return status.code
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,330 @@
1
+ require "boxen/keychain"
2
+ require "boxen/project"
3
+ require "fileutils"
4
+ require "json"
5
+ require "octokit"
6
+ require "shellwords"
7
+
8
+ module Boxen
9
+
10
+ # All configuration for Boxen, whether it's loaded from command-line
11
+ # args, environment variables, config files, or the keychain.
12
+
13
+ class Config
14
+ def self.load(&block)
15
+ new do |config|
16
+ file = "#{config.homedir}/config/boxen/defaults.json"
17
+
18
+ if File.file? file
19
+ attrs = JSON.parse File.read file
20
+
21
+ attrs.each do |key, value|
22
+ if !value.nil? && config.respond_to?(selector = "#{key}=")
23
+ config.send selector, value
24
+ end
25
+ end
26
+ end
27
+
28
+ keychain = Boxen::Keychain.new config.user
29
+ config.token = keychain.token
30
+
31
+ if config.enterprise?
32
+ # configure to talk to GitHub Enterprise
33
+ Octokit.configure do |c|
34
+ c.api_endpoint = "#{config.ghurl}/api/v3"
35
+ c.web_endpoint = config.ghurl
36
+ end
37
+ end
38
+
39
+ yield config if block_given?
40
+ end
41
+ end
42
+
43
+ # Save `config`. Returns `config`. Note that this only saves data,
44
+ # not flags. For example, `login` will be saved, but `stealth?`
45
+ # won't.
46
+
47
+ def self.save(config)
48
+ attrs = {
49
+ :email => config.email,
50
+ :fde => config.fde?,
51
+ :homedir => config.homedir,
52
+ :login => config.login,
53
+ :name => config.name,
54
+ :puppetdir => config.puppetdir,
55
+ :repodir => config.repodir,
56
+ :reponame => config.reponame,
57
+ :ghurl => config.ghurl,
58
+ :srcdir => config.srcdir,
59
+ :user => config.user,
60
+ :repotemplate => config.repotemplate,
61
+ :s3host => config.s3host,
62
+ :s3bucket => config.s3bucket
63
+ }
64
+
65
+ file = "#{config.homedir}/config/boxen/defaults.json"
66
+ FileUtils.mkdir_p File.dirname file
67
+
68
+ File.open file, "wb" do |f|
69
+ f.write JSON.generate Hash[attrs.reject { |k, v| v.nil? }]
70
+ end
71
+
72
+ keychain = Boxen::Keychain.new config.user
73
+ keychain.token = config.token
74
+
75
+ config
76
+ end
77
+
78
+ # Create a new instance. Yields `self` if `block` is given.
79
+
80
+ def initialize(&block)
81
+ @fde = true
82
+ @pull = true
83
+
84
+ yield self if block_given?
85
+ end
86
+
87
+ # Create an API instance using the current user creds. A new
88
+ # instance is created any time `token` changes.
89
+
90
+ def api
91
+ @api ||= Octokit::Client.new :login => token, :password => 'x-oauth-basic'
92
+ end
93
+
94
+ # Spew a bunch of debug logging? Default is `false`.
95
+
96
+ def debug?
97
+ !!@debug
98
+ end
99
+
100
+ attr_writer :debug
101
+
102
+ # A GitHub user's public email.
103
+
104
+ attr_accessor :email
105
+
106
+ # The shell script that loads Boxen's environment.
107
+
108
+ def envfile
109
+ "#{homedir}/env.sh"
110
+ end
111
+
112
+ # Is full disk encryption required? Default is `true`. Respects
113
+ # the `BOXEN_NO_FDE` environment variable.
114
+
115
+ def fde?
116
+ !ENV["BOXEN_NO_FDE"] && @fde
117
+ end
118
+
119
+ attr_writer :fde
120
+
121
+ # Boxen's home directory. Default is `"/opt/boxen"`. Respects the
122
+ # `BOXEN_HOME` environment variable.
123
+
124
+ def homedir
125
+ @homedir || ENV["BOXEN_HOME"] || "/opt/boxen"
126
+ end
127
+
128
+ attr_writer :homedir
129
+
130
+ # Boxen's log file. Default is `"#{repodir}/log/boxen.log"`.
131
+ # Respects the `BOXEN_LOG_FILE` environment variable. The log is
132
+ # overwritten on every run.
133
+
134
+ def logfile
135
+ @logfile || ENV["BOXEN_LOG_FILE"] || "#{repodir}/log/boxen.log"
136
+ end
137
+
138
+ attr_writer :logfile
139
+
140
+ # A GitHub user login. Default is `nil`.
141
+
142
+ attr_accessor :login
143
+
144
+ # A GitHub user's profile name.
145
+
146
+ attr_accessor :name
147
+
148
+ # Just go through the motions? Default is `false`.
149
+
150
+ def pretend?
151
+ !!@pretend
152
+ end
153
+
154
+ attr_writer :pretend
155
+
156
+ # Run a profiler on Puppet? Default is `false`.
157
+
158
+ def profile?
159
+ !!@profile
160
+ end
161
+
162
+ attr_writer :profile
163
+
164
+ # Enable the Puppet future parser? Default is `false`.
165
+
166
+ def future_parser?
167
+ !!@future_parser
168
+ end
169
+
170
+ attr_writer :future_parser
171
+
172
+ # Enable puppet reports ? Default is `false`.
173
+
174
+ def report?
175
+ !!@report
176
+ end
177
+
178
+ attr_writer :report
179
+
180
+ # Enable generation of dependency graphs.
181
+
182
+ def graph?
183
+ !!@graph
184
+ end
185
+
186
+ attr_writer :graph
187
+
188
+ # An Array of Boxen::Project entries, one for each project Boxen
189
+ # knows how to manage.
190
+ #
191
+ # FIX: Revisit this once we restructure template projects. It's
192
+ # broken for several reasons: It assumes paths that won't be
193
+ # right, and it assumes projects live in the same repo as this
194
+ # file.
195
+
196
+ def projects
197
+ files = Dir["#{repodir}/modules/projects/manifests/*.pp"]
198
+ names = files.map { |m| File.basename m, ".pp" }.sort
199
+
200
+ names.map do |name|
201
+ Boxen::Project.new "#{srcdir}/#{name}"
202
+ end
203
+ end
204
+
205
+ # The directory where Puppet expects configuration (which we don't
206
+ # use) and runtime information (which we generally don't care
207
+ # about). Default is `/tmp/boxen/puppet`. Respects the
208
+ # `BOXEN_PUPPET_DIR` environment variable.
209
+
210
+ def puppetdir
211
+ @puppetdir || ENV["BOXEN_PUPPET_DIR"] || "/tmp/boxen/puppet"
212
+ end
213
+
214
+ attr_writer :puppetdir
215
+
216
+ # The directory of the custom Boxen repo for an org. Default is
217
+ # `Dir.pwd`. Respects the `BOXEN_REPO_DIR` environment variable.
218
+
219
+ def repodir
220
+ @repodir || ENV["BOXEN_REPO_DIR"] || Dir.pwd
221
+ end
222
+
223
+ attr_writer :repodir
224
+
225
+ # The repo on GitHub to use for error reports and automatic
226
+ # updates, in `owner/repo` format. Default is the `origin` of a
227
+ # Git repo in `repodir`, if it exists and points at GitHub.
228
+ # Respects the `BOXEN_REPO_NAME` environment variable.
229
+
230
+ def reponame
231
+ override = @reponame || ENV["BOXEN_REPO_NAME"]
232
+ return override unless override.nil?
233
+
234
+ if File.directory? repodir
235
+ ghuri = URI(ghurl)
236
+ url = Dir.chdir(repodir) { `git config remote.origin.url`.strip }
237
+
238
+ # find the path and strip off the .git suffix
239
+ repo_exp = Regexp.new Regexp.escape(ghuri.host) + "[/:]([^/]+/[^/]+)"
240
+ if $?.success? && repo_exp.match(url)
241
+ @reponame = $1.sub /\.git$/, ""
242
+ end
243
+ end
244
+ end
245
+
246
+ attr_writer :reponame
247
+
248
+ # GitHub location (public or GitHub Enterprise)
249
+
250
+ def ghurl
251
+ @ghurl || ENV["BOXEN_GITHUB_ENTERPRISE_URL"] || "https://github.com"
252
+ end
253
+
254
+ attr_writer :ghurl
255
+
256
+ # Repository URL template (required for GitHub Enterprise)
257
+
258
+ def repotemplate
259
+ default = 'https://github.com/%s'
260
+ @repotemplate || ENV["BOXEN_REPO_URL_TEMPLATE"] || default
261
+ end
262
+
263
+ attr_writer :repotemplate
264
+
265
+ # Does this Boxen use a GitHub Enterprise instance?
266
+
267
+ def enterprise?
268
+ ghurl != "https://github.com"
269
+ end
270
+
271
+ # The directory where repos live. Default is
272
+ # `"/Users/#{user}/src"`.
273
+
274
+ def srcdir
275
+ @srcdir || ENV["BOXEN_SRC_DIR"] || "/Users/#{user}/src"
276
+ end
277
+
278
+ attr_writer :srcdir
279
+
280
+ # Don't auto-create issues on failure? Default is `false`.
281
+ # Respects the `BOXEN_NO_ISSUE` environment variable.
282
+
283
+ def stealth?
284
+ !!ENV["BOXEN_NO_ISSUE"] || @stealth
285
+ end
286
+
287
+ attr_writer :stealth
288
+
289
+ # A GitHub OAuth token. Default is `nil`.
290
+
291
+ attr_reader :token
292
+
293
+ def token=(token)
294
+ @token = token
295
+ @api = nil
296
+ end
297
+
298
+ # A local user login. Default is the `USER` environment variable.
299
+
300
+ def user
301
+ @user || ENV["USER"]
302
+ end
303
+
304
+ attr_writer :user
305
+
306
+ def color?
307
+ @color
308
+ end
309
+
310
+ attr_writer :color
311
+
312
+ # The S3 host name. Default is `"s3.amazonaws.com"`.
313
+ # Respects the `BOXEN_S3_HOST` environment variable.
314
+
315
+ def s3host
316
+ @s3host || ENV["BOXEN_S3_HOST"] || "s3.amazonaws.com"
317
+ end
318
+
319
+ attr_writer :s3host
320
+
321
+ # The S3 bucket name. Default is `"boxen-downloads"`.
322
+ # Respects the `BOXEN_S3_BUCKET` environment variable.
323
+
324
+ def s3bucket
325
+ @s3bucket || ENV["BOXEN_S3_BUCKET"] || "boxen-downloads"
326
+ end
327
+
328
+ attr_writer :s3bucket
329
+ end
330
+ end