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.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.travis.yml +7 -0
- data/Gemfile +2 -0
- data/LICENSE +20 -0
- data/README.md +50 -0
- data/boxen.gemspec +26 -0
- data/lib/boxen/check.rb +72 -0
- data/lib/boxen/checkout.rb +25 -0
- data/lib/boxen/cli.rb +63 -0
- data/lib/boxen/config.rb +330 -0
- data/lib/boxen/error.rb +4 -0
- data/lib/boxen/flags.rb +272 -0
- data/lib/boxen/hook.rb +47 -0
- data/lib/boxen/hook/github_issue.rb +120 -0
- data/lib/boxen/hook/web.rb +56 -0
- data/lib/boxen/keychain.rb +63 -0
- data/lib/boxen/postflight.rb +13 -0
- data/lib/boxen/postflight/active.rb +16 -0
- data/lib/boxen/postflight/env.rb +34 -0
- data/lib/boxen/preflight.rb +13 -0
- data/lib/boxen/preflight/creds.rb +108 -0
- data/lib/boxen/preflight/directories.rb +32 -0
- data/lib/boxen/preflight/etc_my_cnf.rb +12 -0
- data/lib/boxen/preflight/homebrew.rb +13 -0
- data/lib/boxen/preflight/identity.rb +16 -0
- data/lib/boxen/preflight/os.rb +33 -0
- data/lib/boxen/preflight/rbenv.rb +12 -0
- data/lib/boxen/preflight/rvm.rb +12 -0
- data/lib/boxen/project.rb +20 -0
- data/lib/boxen/puppeteer.rb +122 -0
- data/lib/boxen/runner.rb +149 -0
- data/lib/boxen/service.rb +58 -0
- data/lib/boxen/util.rb +17 -0
- data/lib/facter/boxen.rb +34 -0
- data/lib/system_timer.rb +13 -0
- data/script/Boxen +0 -0
- data/script/Boxen-linux +0 -0
- data/script/bootstrap +7 -0
- data/script/build-keychain-helper +6 -0
- data/script/build-keyring-helper +9 -0
- data/script/release +38 -0
- data/script/tests +10 -0
- data/src/keychain-helper.c +85 -0
- data/src/keyring-helper.c +86 -0
- data/test/boxen/test.rb +7 -0
- data/test/boxen_check_test.rb +55 -0
- data/test/boxen_checkout_test.rb +42 -0
- data/test/boxen_cli_test.rb +39 -0
- data/test/boxen_config_test.rb +393 -0
- data/test/boxen_directories_test.rb +40 -0
- data/test/boxen_flags_test.rb +217 -0
- data/test/boxen_hook_github_issue_test.rb +294 -0
- data/test/boxen_hook_web_test.rb +58 -0
- data/test/boxen_keychain_test.rb +24 -0
- data/test/boxen_postflight_active_test.rb +29 -0
- data/test/boxen_postflight_env_test.rb +6 -0
- data/test/boxen_preflight_creds_test.rb +80 -0
- data/test/boxen_preflight_etc_my_cnf_test.rb +10 -0
- data/test/boxen_preflight_homebrew_test.rb +10 -0
- data/test/boxen_preflight_rvm_test.rb +10 -0
- data/test/boxen_project_test.rb +14 -0
- data/test/boxen_puppeteer_test.rb +101 -0
- data/test/boxen_runner_test.rb +171 -0
- data/test/boxen_service_test.rb +39 -0
- data/test/boxen_util_test.rb +21 -0
- data/test/fixtures/repo/modules/projects/manifests/first-project.pp +0 -0
- data/test/fixtures/repo/modules/projects/manifests/second-project.pp +0 -0
- data/test/system_timer.rb +10 -0
- metadata +279 -0
@@ -0,0 +1,63 @@
|
|
1
|
+
require "shellwords"
|
2
|
+
|
3
|
+
module Boxen
|
4
|
+
class Keychain
|
5
|
+
|
6
|
+
# The keychain proxy we use to provide isolation and a friendly
|
7
|
+
# message in security prompts.
|
8
|
+
if (/darwin/ =~ RUBY_PLATFORM) != nil
|
9
|
+
HELPER = File.expand_path "../../../script/Boxen", __FILE__
|
10
|
+
else
|
11
|
+
HELPER = File.expand_path "../../../script/Boxen-linux", __FILE__
|
12
|
+
end
|
13
|
+
|
14
|
+
# The service name to use when loading/saving passwords.
|
15
|
+
|
16
|
+
PASSWORD_SERVICE = "GitHub Password"
|
17
|
+
|
18
|
+
# The service name to use when loading/saving API keys.
|
19
|
+
|
20
|
+
TOKEN_SERVICE = "GitHub API Token"
|
21
|
+
|
22
|
+
def initialize(login)
|
23
|
+
@login = login
|
24
|
+
# Clear the password. We're storing tokens now.
|
25
|
+
set PASSWORD_SERVICE, ""
|
26
|
+
end
|
27
|
+
|
28
|
+
def token
|
29
|
+
get TOKEN_SERVICE
|
30
|
+
end
|
31
|
+
|
32
|
+
def token=(token)
|
33
|
+
set TOKEN_SERVICE, token
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
attr_reader :login
|
39
|
+
|
40
|
+
def get(service)
|
41
|
+
print 'get', HELPER, service, login
|
42
|
+
cmd = shellescape(HELPER, service, login)
|
43
|
+
|
44
|
+
result = `#{cmd}`.strip
|
45
|
+
$?.success? ? result : nil
|
46
|
+
end
|
47
|
+
|
48
|
+
def set(service, token)
|
49
|
+
print 'set', HELPER, service, login, token
|
50
|
+
cmd = shellescape(HELPER, service, login, token)
|
51
|
+
|
52
|
+
unless system *cmd
|
53
|
+
raise Boxen::Error, "Can't save #{service} in the keychain."
|
54
|
+
end
|
55
|
+
|
56
|
+
token
|
57
|
+
end
|
58
|
+
|
59
|
+
def shellescape(*args)
|
60
|
+
args.map { |s| Shellwords.shellescape s }.join " "
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "boxen/postflight"
|
2
|
+
require "boxen/util"
|
3
|
+
|
4
|
+
# Checks to see if the basic environment is loaded.
|
5
|
+
|
6
|
+
class Boxen::Postflight::Active < Boxen::Postflight
|
7
|
+
def ok?
|
8
|
+
Boxen::Util.active?
|
9
|
+
end
|
10
|
+
|
11
|
+
def run
|
12
|
+
warn "You haven't loaded Boxen's environment yet!",
|
13
|
+
"To permanently fix this, source #{config.envfile} at the end",
|
14
|
+
"of your shell's startup file."
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "boxen/postflight"
|
2
|
+
|
3
|
+
class Boxen::Postflight::Env < Boxen::Postflight
|
4
|
+
|
5
|
+
# Calculate an MD5 checksum for the current environment.
|
6
|
+
|
7
|
+
def self.checksum
|
8
|
+
|
9
|
+
# We can't get this from config 'cause it's static (gotta happen
|
10
|
+
# on load), and BOXEN_HOME might not be set.
|
11
|
+
|
12
|
+
home = ENV["BOXEN_HOME"] || "/opt/boxen"
|
13
|
+
return unless File.file? "#{home}/env.sh"
|
14
|
+
if RUBY_PLATFORM =~ /Darwin/
|
15
|
+
`find #{home}/env* -type f 2>&1 | sort | xargs /sbin/md5 | /sbin/md5 -q`.strip
|
16
|
+
elsif RUBY_PLATFORM =~ /Debian/
|
17
|
+
#TODO: figure out linux equivalent of above darwin line. maybe:
|
18
|
+
`find #{home}/env* -type f 2>&1 | sort | xargs /usr/bin/md5sum | /usr/bin/md5sum --quiet`.strip
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
# The checksum when this file was loaded.
|
24
|
+
|
25
|
+
CHECKSUM = self.checksum
|
26
|
+
|
27
|
+
def ok?
|
28
|
+
self.class.checksum == CHECKSUM
|
29
|
+
end
|
30
|
+
|
31
|
+
def run
|
32
|
+
warn "Source #{config.envfile} or restart your shell for new stuff!"
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require "boxen/preflight"
|
2
|
+
require "highline"
|
3
|
+
require "octokit"
|
4
|
+
|
5
|
+
# HACK: Unless this is `false`, HighLine has some really bizarre
|
6
|
+
# problems with empty/expended streams at bizarre intervals.
|
7
|
+
|
8
|
+
HighLine.track_eof = false
|
9
|
+
|
10
|
+
class Boxen::Preflight::Creds < Boxen::Preflight
|
11
|
+
attr :otp
|
12
|
+
attr :password
|
13
|
+
|
14
|
+
def ok?
|
15
|
+
if config.token && config.api.user
|
16
|
+
# There was a period of time when login wasn't geting set on first run.
|
17
|
+
# This should correct that.
|
18
|
+
config.login = config.api.user.login
|
19
|
+
true
|
20
|
+
end
|
21
|
+
rescue
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def tmp_api
|
26
|
+
@tmp_api ||= Octokit::Client.new :login => config.login, :password => password, :auto_paginate => true
|
27
|
+
end
|
28
|
+
|
29
|
+
def headers
|
30
|
+
otp.nil? ? {} : {"X-GitHub-OTP" => otp}
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_otp
|
34
|
+
console = HighLine.new
|
35
|
+
|
36
|
+
# junk API call to send OTP until we implement PUT
|
37
|
+
tmp_api.create_authorization rescue nil
|
38
|
+
|
39
|
+
@otp = console.ask "One time password (via SMS or device):" do |q|
|
40
|
+
q.echo = '*'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Attempt to use the username+password to get a list of the user's OAuth
|
45
|
+
# authorizations from the API. If it fails because of 2FA, ask the user for
|
46
|
+
# her OTP and try again.
|
47
|
+
#
|
48
|
+
# Returns a list of authorizations
|
49
|
+
def get_tokens
|
50
|
+
begin
|
51
|
+
tmp_api.authorizations(:headers => headers)
|
52
|
+
rescue Octokit::Unauthorized
|
53
|
+
abort "Sorry, I can't auth you on GitHub.",
|
54
|
+
"Please check your credentials and teams and give it another try."
|
55
|
+
rescue Octokit::OneTimePasswordRequired
|
56
|
+
puts
|
57
|
+
if otp.nil?
|
58
|
+
warn "It looks like you have two-factor auth enabled."
|
59
|
+
else
|
60
|
+
warn "That one time password didn't work. Let's try again."
|
61
|
+
end
|
62
|
+
get_otp
|
63
|
+
get_tokens
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def run
|
68
|
+
fetch_login_and_password
|
69
|
+
tokens = get_tokens
|
70
|
+
|
71
|
+
unless auth = tokens.detect { |a| a.note == "Boxen" }
|
72
|
+
auth = tmp_api.create_authorization \
|
73
|
+
:note => "Boxen",
|
74
|
+
:scopes => %w(repo user),
|
75
|
+
:headers => headers
|
76
|
+
end
|
77
|
+
|
78
|
+
config.token = auth.token
|
79
|
+
|
80
|
+
unless ok?
|
81
|
+
puts
|
82
|
+
abort "Something went terribly wrong.",
|
83
|
+
"I was able to get your OAuth token, but was unable to use it."
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def fetch_login_and_password
|
90
|
+
console = HighLine.new
|
91
|
+
|
92
|
+
config.login = fetch_from_env("login") || console.ask("GitHub login: ") do |q|
|
93
|
+
q.default = config.login || config.user
|
94
|
+
q.validate = /\A[^@]+\Z/
|
95
|
+
end
|
96
|
+
|
97
|
+
@password = fetch_from_env("password") || console.ask("GitHub password: ") do |q|
|
98
|
+
q.echo = "*"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def fetch_from_env(thing)
|
103
|
+
key = "BOXEN_GITHUB_#{thing.upcase}"
|
104
|
+
return unless found = ENV[key]
|
105
|
+
warn "Oh, looks like you've provided your #{thing} as environmental variable..."
|
106
|
+
found
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "boxen/preflight"
|
2
|
+
require "boxen/util"
|
3
|
+
|
4
|
+
class Boxen::Preflight::Directories < Boxen::Preflight
|
5
|
+
def ok?
|
6
|
+
homedir_directory_exists? &&
|
7
|
+
homedir_owner == config.user &&
|
8
|
+
homedir_group == 'staff'
|
9
|
+
end
|
10
|
+
|
11
|
+
def run
|
12
|
+
Boxen::Util.sudo("/bin/mkdir", "-p", config.homedir) &&
|
13
|
+
Boxen::Util.sudo("/usr/sbin/chown", "#{config.user}:staff", config.homedir)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def homedir_directory_exists?
|
18
|
+
File.directory?(config.homedir)
|
19
|
+
end
|
20
|
+
|
21
|
+
def homedir_owner
|
22
|
+
Etc.getpwuid(homedir_stat.uid).name
|
23
|
+
end
|
24
|
+
|
25
|
+
def homedir_group
|
26
|
+
Etc.getgrgid(homedir_stat.gid).name
|
27
|
+
end
|
28
|
+
|
29
|
+
def homedir_stat
|
30
|
+
@homedir_stat ||= File.stat(config.homedir)
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "boxen/preflight"
|
2
|
+
|
3
|
+
class Boxen::Preflight::Homebrew < Boxen::Preflight
|
4
|
+
def run
|
5
|
+
warn "You have an existing Homebrew install in /usr/local",
|
6
|
+
"The Boxen provides its own Homebrew, so consider deleting yours.",
|
7
|
+
"Keeping both will confuse many projects."
|
8
|
+
end
|
9
|
+
|
10
|
+
def ok?
|
11
|
+
!File.exist? "/usr/local/Library/Homebrew"
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "boxen/preflight"
|
2
|
+
|
3
|
+
class Boxen::Preflight::Identity < Boxen::Preflight
|
4
|
+
def ok?
|
5
|
+
!user || (config.email && config.name)
|
6
|
+
end
|
7
|
+
|
8
|
+
def run
|
9
|
+
config.email = user.email
|
10
|
+
config.name = user.name
|
11
|
+
end
|
12
|
+
|
13
|
+
def user
|
14
|
+
@user ||= config.api.user rescue nil
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "boxen/preflight"
|
2
|
+
|
3
|
+
class Boxen::Preflight::OS < Boxen::Preflight
|
4
|
+
SUPPORTED_RELEASES = %w(10.8 10.9)
|
5
|
+
|
6
|
+
def ok?
|
7
|
+
(linux? || (osx? && supported_release?))
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
abort "You must be running one of the following OS X versions: #{SUPPORTED_RELEASES.join(' ')}."
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def osx?
|
17
|
+
`uname -s`.chomp == "Darwin"
|
18
|
+
end
|
19
|
+
|
20
|
+
def linux?
|
21
|
+
`uname -s`.chomp == "Linux"
|
22
|
+
end
|
23
|
+
|
24
|
+
def supported_release?
|
25
|
+
SUPPORTED_RELEASES.any? do |r|
|
26
|
+
current_release.start_with? r
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def current_release
|
31
|
+
@current_release ||= `sw_vers -productVersion`
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "boxen/preflight"
|
2
|
+
|
3
|
+
class Boxen::Preflight::Rbenv < Boxen::Preflight
|
4
|
+
def run
|
5
|
+
warn "You have an existing rbenv installed in ~/.rbenv.",
|
6
|
+
"Boxen provides its own rbenv, so consider deleting yours."
|
7
|
+
end
|
8
|
+
|
9
|
+
def ok?
|
10
|
+
!File.exist? "#{ENV['HOME']}/.rbenv"
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "boxen/preflight"
|
2
|
+
|
3
|
+
class Boxen::Preflight::RVM < Boxen::Preflight
|
4
|
+
def run
|
5
|
+
abort "You have an rvm installed in ~/.rvm.",
|
6
|
+
"Boxen uses rbenv to install ruby, so please `rvm implode`"
|
7
|
+
end
|
8
|
+
|
9
|
+
def ok?
|
10
|
+
!File.exist? "#{ENV['HOME']}/.rvm"
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Boxen
|
2
|
+
|
3
|
+
# A project managed by Boxen.
|
4
|
+
|
5
|
+
class Project
|
6
|
+
|
7
|
+
# The directory where this project's repo should live.
|
8
|
+
|
9
|
+
attr_reader :dir
|
10
|
+
|
11
|
+
# The name of this project.
|
12
|
+
|
13
|
+
attr_reader :name
|
14
|
+
|
15
|
+
def initialize(dir)
|
16
|
+
@dir = dir
|
17
|
+
@name = File.basename @dir
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "boxen/util"
|
3
|
+
|
4
|
+
module Boxen
|
5
|
+
|
6
|
+
# Manages an invocation of puppet.
|
7
|
+
|
8
|
+
class Puppeteer
|
9
|
+
|
10
|
+
class Status < Struct.new(:code)
|
11
|
+
# Puppet's detailed exit codes reserves 2 for a successful run with changes
|
12
|
+
def success?
|
13
|
+
[0,2].include?(code)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :config
|
18
|
+
|
19
|
+
def initialize(config)
|
20
|
+
@config = config
|
21
|
+
end
|
22
|
+
|
23
|
+
def command
|
24
|
+
manifest = "#{config.repodir}/manifests/site.pp"
|
25
|
+
puppet = "#{config.repodir}/bin/puppet"
|
26
|
+
|
27
|
+
[puppet, "apply", flags, manifest].flatten
|
28
|
+
end
|
29
|
+
|
30
|
+
def hiera_config
|
31
|
+
if File.exist? "#{config.repodir}/config/hiera.yaml"
|
32
|
+
"#{config.repodir}/config/hiera.yaml"
|
33
|
+
else
|
34
|
+
"/dev/null"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def flags
|
39
|
+
flags = []
|
40
|
+
root = File.expand_path "../../..", __FILE__
|
41
|
+
|
42
|
+
flags << ["--group", "admin"]
|
43
|
+
flags << ["--confdir", "#{config.puppetdir}/conf"]
|
44
|
+
flags << ["--vardir", "#{config.puppetdir}/var"]
|
45
|
+
flags << ["--libdir", "#{config.repodir}/lib"]#:#{root}/lib"]
|
46
|
+
flags << ["--libdir", "#{root}/lib"]
|
47
|
+
flags << ["--manifestdir", "#{config.repodir}/manifests"]
|
48
|
+
flags << ["--modulepath", "#{config.repodir}/modules:#{config.repodir}/shared"]
|
49
|
+
|
50
|
+
# Don't ever complain about Hiera to me
|
51
|
+
flags << ["--hiera_config", hiera_config]
|
52
|
+
|
53
|
+
# Log to both the console and a file.
|
54
|
+
|
55
|
+
flags << ["--logdest", config.logfile]
|
56
|
+
flags << ["--logdest", "console"]
|
57
|
+
|
58
|
+
# For some reason Puppet tries to set up a bunch of rrd stuff
|
59
|
+
# (user, group) unless reports are completely disabled.
|
60
|
+
|
61
|
+
flags << "--no-report" unless config.report?
|
62
|
+
flags << "--detailed-exitcodes"
|
63
|
+
|
64
|
+
flags << "--graph" if config.graph?
|
65
|
+
|
66
|
+
flags << "--show_diff"
|
67
|
+
|
68
|
+
if config.profile?
|
69
|
+
flags << "--evaltrace"
|
70
|
+
flags << "--summarize"
|
71
|
+
end
|
72
|
+
|
73
|
+
if config.future_parser?
|
74
|
+
flags << "--parser=future"
|
75
|
+
end
|
76
|
+
|
77
|
+
flags << "--debug" if config.debug?
|
78
|
+
flags << "--noop" if config.pretend?
|
79
|
+
|
80
|
+
flags << "--color=false" unless config.color?
|
81
|
+
|
82
|
+
flags.flatten
|
83
|
+
end
|
84
|
+
|
85
|
+
def run
|
86
|
+
FileUtils.mkdir_p config.puppetdir
|
87
|
+
|
88
|
+
FileUtils.rm_f config.logfile
|
89
|
+
|
90
|
+
FileUtils.rm_rf "#{config.puppetdir}/var/reports" if config.report?
|
91
|
+
|
92
|
+
FileUtils.rm_rf "#{config.puppetdir}/var/state/graphs" if config.graph?
|
93
|
+
|
94
|
+
FileUtils.mkdir_p File.dirname config.logfile
|
95
|
+
FileUtils.touch config.logfile
|
96
|
+
|
97
|
+
if File.file? "Puppetfile"
|
98
|
+
librarian = "#{config.repodir}/bin/librarian-puppet"
|
99
|
+
|
100
|
+
unless config.enterprise?
|
101
|
+
# Set an environment variable for librarian-puppet's
|
102
|
+
# github_tarball source strategy.
|
103
|
+
ENV["GITHUB_API_TOKEN"] = config.token
|
104
|
+
end
|
105
|
+
|
106
|
+
librarian_command = [librarian, "install", "--path=#{config.repodir}/shared"]
|
107
|
+
librarian_command << "--verbose" if config.debug?
|
108
|
+
|
109
|
+
warn librarian_command.join(" ") if config.debug?
|
110
|
+
unless system *librarian_command
|
111
|
+
abort "Can't run Puppet, fetching dependencies with librarian failed."
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
warn command.join(" ") if config.debug?
|
116
|
+
|
117
|
+
Boxen::Util.sudo *command
|
118
|
+
|
119
|
+
Status.new($?.exitstatus)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|