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,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,13 @@
1
+ require "boxen/check"
2
+
3
+ module Boxen
4
+
5
+ # The superclass for postflight checks.
6
+
7
+ class Postflight < Boxen::Check
8
+
9
+ # Load all available postflight checks.
10
+
11
+ register File.expand_path("../postflight", __FILE__)
12
+ end
13
+ 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,13 @@
1
+ require "boxen/check"
2
+
3
+ module Boxen
4
+
5
+ # The superclass for preflight checks.
6
+
7
+ class Preflight < Boxen::Check
8
+
9
+ # Load all available preflight checks.
10
+
11
+ register File.expand_path("../preflight", __FILE__)
12
+ end
13
+ 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,12 @@
1
+ require "boxen/preflight"
2
+
3
+ class Boxen::Preflight::EtcMyCnf < Boxen::Preflight
4
+ def run
5
+ abort "You have an /etc/my.cnf file.",
6
+ "This will confuse Boxen's MySQL a lot. Please remove it."
7
+ end
8
+
9
+ def ok?
10
+ !File.file? "/etc/my.cnf"
11
+ end
12
+ 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