boxen 0.0.0

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.
@@ -0,0 +1,4 @@
1
+ /.bundle
2
+ /.rbenv-version
3
+ /bin
4
+ /boxen-*.gem
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec
@@ -0,0 +1,49 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ boxen (0.0.0)
5
+ ansi (~> 1.4)
6
+ highline (~> 1.6)
7
+ json_pure (~> 1.7)
8
+ octokit (~> 1.15)
9
+ puppet (~> 3.0)
10
+
11
+ GEM
12
+ remote: http://rubygems.org/
13
+ specs:
14
+ addressable (2.3.2)
15
+ ansi (1.4.3)
16
+ facter (1.6.12)
17
+ faraday (0.8.4)
18
+ multipart-post (~> 1.1)
19
+ faraday_middleware (0.8.8)
20
+ faraday (>= 0.7.4, < 0.9)
21
+ hashie (1.2.0)
22
+ hiera (1.1.0.rc1)
23
+ json
24
+ highline (1.6.15)
25
+ json (1.7.5)
26
+ json_pure (1.7.5)
27
+ metaclass (0.0.1)
28
+ minitest (3.5.0)
29
+ mocha (0.12.6)
30
+ metaclass (~> 0.0.1)
31
+ multi_json (1.3.6)
32
+ multipart-post (1.1.5)
33
+ octokit (1.15.1)
34
+ addressable (~> 2.2)
35
+ faraday (~> 0.8)
36
+ faraday_middleware (~> 0.8)
37
+ hashie (~> 1.2)
38
+ multi_json (~> 1.3)
39
+ puppet (3.0.0)
40
+ facter (>= 1.6.11)
41
+ hiera (>= 1.0.0rc)
42
+
43
+ PLATFORMS
44
+ ruby
45
+
46
+ DEPENDENCIES
47
+ boxen!
48
+ minitest (= 3.5.0)
49
+ mocha (~> 0.12)
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,7 @@
1
+ # Boxen
2
+
3
+ Manage development boxes with love (and Puppet).
4
+
5
+ ## Contributing
6
+
7
+ Use the OS X system Ruby (1.8.7). Run `script/tests` often. Open PR's.
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "boxen"
5
+ gem.version = "0.0.0"
6
+ gem.authors = ["John Barnette", "Will Farrington"]
7
+ gem.email = ["jbarnette@github.com", "wfarr@github.com"]
8
+ gem.description = "Manage Mac 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 "highline", "~> 1.6"
18
+ gem.add_dependency "json_pure", "~> 1.7"
19
+ gem.add_dependency "octokit", "~> 1.15"
20
+ gem.add_dependency "puppet", "~> 3.0"
21
+
22
+ gem.add_development_dependency "minitest", "3.5.0" # pinned for mocha
23
+ gem.add_development_dependency "mocha", "~> 0.12"
24
+ 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,79 @@
1
+ require "boxen/config"
2
+ require "boxen/flags"
3
+ require "boxen/postflight"
4
+ require "boxen/preflight"
5
+ require "boxen/puppeteer"
6
+
7
+ module Boxen
8
+ class CLI
9
+ attr_reader :config
10
+ attr_reader :flags
11
+ attr_reader :puppet
12
+
13
+ def initialize(config, flags)
14
+ @config = config
15
+ @flags = flags
16
+ @puppet = Boxen::Puppeteer.new @config
17
+ end
18
+
19
+ def run
20
+
21
+ # --env prints out the current BOXEN_ env vars.
22
+
23
+ exec "env | grep ^BOXEN_ | sort" if flags.env?
24
+
25
+ # --help prints some CLI help and exits.
26
+
27
+ abort "#{flags}\n" if flags.help?
28
+
29
+ # --projects prints a list of available projects and exits.
30
+
31
+ if flags.projects?
32
+ config.projects.each do |project|
33
+ prefix = project.installed? ? "*" : " "
34
+ puts "#{prefix} #{project.name}"
35
+ end
36
+
37
+ exit
38
+ end
39
+
40
+ status = puppet.run
41
+
42
+ return status
43
+ end
44
+
45
+ # Run Boxen by wiring together the command-line flags, config,
46
+ # preflights, Puppet execution, and postflights. Returns Puppet's
47
+ # exit code.
48
+
49
+ def self.run(*args)
50
+ config = Boxen::Config.load
51
+ flags = Boxen::Flags.new args
52
+
53
+ # Apply command-line flags to the config in case we're changing or
54
+ # overriding anything.
55
+
56
+ flags.apply config
57
+
58
+ # Run the preflight checks.
59
+
60
+ Boxen::Preflight.run config
61
+
62
+ # Save the config for Puppet (and next time).
63
+
64
+ Boxen::Config.save config
65
+
66
+ # Make the magic happen.
67
+
68
+ status = Boxen::CLI.new(config, flags).run
69
+
70
+ # Run the postflight checks.
71
+
72
+ Boxen::Postflight.run config if status.zero?
73
+
74
+ # Return Puppet's exit status.
75
+
76
+ return status
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,251 @@
1
+ require "fileutils"
2
+ require "json"
3
+ require "octokit"
4
+ require "boxen/project"
5
+
6
+ module Boxen
7
+
8
+ # All configuration for Boxen, whether it's loaded from command-line
9
+ # args, environment variables, config files, or the keychain.
10
+
11
+ class Config
12
+
13
+ # The service name to use when loading/saving config in the Keychain.
14
+
15
+ KEYCHAIN_SERVICE = "Boxen"
16
+
17
+ # Load config. Yields config if `block` is given.
18
+
19
+ def self.load(&block)
20
+ new do |config|
21
+ file = "#{config.homedir}/config/boxen/defaults.json"
22
+
23
+ if File.file? file
24
+ attrs = JSON.parse File.read file
25
+
26
+ attrs.each do |key, value|
27
+ if value && config.respond_to?(selector = "#{key}=")
28
+ config.send selector, value
29
+ end
30
+ end
31
+ end
32
+
33
+ cmd = "security find-generic-password " +
34
+ "-a #{config.user} -s '#{KEYCHAIN_SERVICE}' -w 2>/dev/null"
35
+
36
+ password = `#{cmd}`.strip
37
+ password = nil unless $?.success?
38
+
39
+ config.password = password
40
+
41
+ yield config if block_given?
42
+ end
43
+ end
44
+
45
+ # Save `config`. Returns `config`. Note that this only saves data,
46
+ # not flags. For example, `login` will be saved, but `stealth?`
47
+ # won't.
48
+
49
+ def self.save(config)
50
+ attrs = {
51
+ :email => config.email,
52
+ :homedir => config.homedir,
53
+ :login => config.login,
54
+ :name => config.name,
55
+ :puppetdir => config.puppetdir,
56
+ :repodir => config.repodir,
57
+ :srcdir => config.srcdir,
58
+ :user => config.user
59
+ }
60
+
61
+ file = "#{config.homedir}/config/boxen/defaults.json"
62
+ FileUtils.mkdir_p File.dirname file
63
+
64
+ File.open file, "wb" do |f|
65
+ f.write JSON.generate Hash[attrs.reject { |k, v| v.nil? }]
66
+ end
67
+
68
+ cmd = ["security", "add-generic-password",
69
+ "-a", config.user, "-s", KEYCHAIN_SERVICE, "-U", "-w", config.password]
70
+
71
+ unless system *cmd
72
+ raise Boxen::Error, "Can't save config in the Keychain."
73
+ end
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 `login` or `password` change.
89
+
90
+ def api
91
+ @api ||= Octokit::Client.new :login => login, :password => password
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
+ def dirty?
103
+ `git status --porcelain`.strip.empty?
104
+ end
105
+
106
+ # A GitHub user's public email.
107
+
108
+ attr_accessor :email
109
+
110
+ # The shell script that loads Boxen's environment.
111
+
112
+ def envfile
113
+ "#{homedir}/env.sh"
114
+ end
115
+
116
+ # Is full disk encryption required? Default is `true`. Respects
117
+ # the `BOXEN_NO_FDE` environment variable.
118
+
119
+ def fde?
120
+ !ENV["BOXEN_NO_FDE"] && @fde
121
+ end
122
+
123
+ attr_writer :fde
124
+
125
+ # Boxen's home directory. Default is `"/opt/boxen"`. Respects the
126
+ # `BOXEN_HOME` environment variable.
127
+
128
+ def homedir
129
+ @homedir || ENV["BOXEN_HOME"] || "/opt/boxen"
130
+ end
131
+
132
+ attr_writer :homedir
133
+
134
+ # Boxen's log file. Default is `"#{repodir}/log/boxen.log"`.
135
+ # Respects the `BOXEN_LOG_FILE` environment variable. The log is
136
+ # overwritten on every run.
137
+
138
+ def logfile
139
+ @logfile || ENV["BOXEN_LOG_FILE"] || "#{repodir}/log/boxen.log"
140
+ end
141
+
142
+ attr_writer :logfile
143
+
144
+ # A GitHub user login. Default is `nil`.
145
+
146
+ attr_reader :login
147
+
148
+ def login=(login)
149
+ @api = nil
150
+ @login = login
151
+ end
152
+
153
+ # Is Boxen running on the `master` branch?
154
+
155
+ def master?
156
+ `git symbolic-ref HEAD`.chomp == "refs/heads/master"
157
+ end
158
+
159
+ # A GitHub user's profile name.
160
+
161
+ attr_accessor :name
162
+
163
+ # A GitHub user password. Default is `nil`.
164
+
165
+ attr_reader :password
166
+
167
+ def password=(password)
168
+ @api = nil
169
+ @password = password
170
+ end
171
+
172
+ # Just go through the motions? Default is `false`.
173
+
174
+ def pretend?
175
+ !!@pretend
176
+ end
177
+
178
+ attr_writer :pretend
179
+
180
+ # Run a profiler on Puppet? Default is `false`.
181
+
182
+ def profile?
183
+ !!@profile
184
+ end
185
+
186
+ attr_writer :profile
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 directory where repos live. Default is
226
+ # `"/Users/#{user}/src"`.
227
+
228
+ def srcdir
229
+ @srcdir || "/Users/#{user}/src"
230
+ end
231
+
232
+ attr_writer :srcdir
233
+
234
+ # Don't auto-create issues on failure? Default is `false`.
235
+ # Respects the `BOXEN_NO_ISSUE` environment variable.
236
+
237
+ def stealth?
238
+ !!ENV["BOXEN_NO_ISSUE"] || @stealth
239
+ end
240
+
241
+ attr_writer :stealth
242
+
243
+ # A local user login. Default is the `USER` environment variable.
244
+
245
+ def user
246
+ @user || ENV["USER"]
247
+ end
248
+
249
+ attr_writer :user
250
+ end
251
+ end