boxen 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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