mirror of
https://github.com/zhigang1992/boxen.git
synced 2026-01-12 08:54:07 +08:00
Add a model for config
This commit is contained in:
17
Gemfile.lock
17
Gemfile.lock
@@ -2,14 +2,31 @@ PATH
|
||||
remote: .
|
||||
specs:
|
||||
boxen (0.0.0)
|
||||
json_pure
|
||||
octokit
|
||||
|
||||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
addressable (2.3.2)
|
||||
faraday (0.8.4)
|
||||
multipart-post (~> 1.1)
|
||||
faraday_middleware (0.8.8)
|
||||
faraday (>= 0.7.4, < 0.9)
|
||||
hashie (1.2.0)
|
||||
json_pure (1.7.5)
|
||||
metaclass (0.0.1)
|
||||
minitest (3.5.0)
|
||||
mocha (0.12.6)
|
||||
metaclass (~> 0.0.1)
|
||||
multi_json (1.3.6)
|
||||
multipart-post (1.1.5)
|
||||
octokit (1.15.1)
|
||||
addressable (~> 2.2)
|
||||
faraday (~> 0.8)
|
||||
faraday_middleware (~> 0.8)
|
||||
hashie (~> 1.2)
|
||||
multi_json (~> 1.3)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
@@ -13,6 +13,9 @@ Gem::Specification.new do |gem|
|
||||
gem.test_files = gem.files.grep /^test/
|
||||
gem.require_paths = ["lib"]
|
||||
|
||||
gem.add_dependency "json_pure"
|
||||
gem.add_dependency "octokit"
|
||||
|
||||
gem.add_development_dependency "minitest", "3.5.0"
|
||||
gem.add_development_dependency "mocha"
|
||||
end
|
||||
|
||||
235
lib/boxen/config.rb
Normal file
235
lib/boxen/config.rb
Normal file
@@ -0,0 +1,235 @@
|
||||
require "fileutils"
|
||||
require "json"
|
||||
require "octokit"
|
||||
require "boxen/project"
|
||||
|
||||
module Boxen
|
||||
|
||||
# All configuration for Boxen, whether it's loaded from command-line
|
||||
# args, environment variables, config files, or the keychain.
|
||||
|
||||
class Config
|
||||
|
||||
# The service name to use when loading/saving config in the Keychain.
|
||||
|
||||
KEYCHAIN_SERVICE = "Boxen"
|
||||
|
||||
# Load config. Yields config if `block` is given.
|
||||
|
||||
def self.load(&block)
|
||||
new do |config|
|
||||
home = ENV["GH_HOME"] || "/opt/boxen"
|
||||
file = "#{home}/config/boxen/defaults.json"
|
||||
|
||||
if File.file? file
|
||||
attrs = JSON.parse File.read file
|
||||
|
||||
attrs.each do |key, value|
|
||||
if value && config.respond_to?(selector = "#{key}=")
|
||||
config.send selector, value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
cmd = "security find-generic-password " +
|
||||
"-a #{config.user} -s '#{KEYCHAIN_SERVICE}' -w 2>/dev/null"
|
||||
|
||||
password = `#{cmd}`.strip
|
||||
password = nil unless $?.success?
|
||||
|
||||
config.password = password
|
||||
|
||||
yield config if block_given?
|
||||
end
|
||||
end
|
||||
|
||||
# Save `config`. Returns `config`. Note that this only saves data,
|
||||
# not flags. For example, `login` will be saved, but `stealth?`
|
||||
# won't.
|
||||
|
||||
def self.save(config)
|
||||
attrs = {
|
||||
:email => config.email,
|
||||
:homedir => config.homedir,
|
||||
:login => config.login,
|
||||
:name => config.name,
|
||||
:srcdir => config.srcdir,
|
||||
:user => config.user
|
||||
}
|
||||
|
||||
file = "#{config.homedir}/config/boxen/defaults.json"
|
||||
FileUtils.mkdir_p File.dirname file
|
||||
|
||||
File.open file, "wb" do |f|
|
||||
f.write JSON.generate Hash[attrs.reject { |k, v| v.nil? }]
|
||||
end
|
||||
|
||||
cmd = ["security", "add-generic-password",
|
||||
"-a", config.user, "-s", KEYCHAIN_SERVICE, "-U", "-w", config.password]
|
||||
|
||||
unless system *cmd
|
||||
raise Boxen::Error, "Can't save config in the Keychain."
|
||||
end
|
||||
|
||||
config
|
||||
end
|
||||
|
||||
# Create a new instance. Yields `self` if `block` is given.
|
||||
|
||||
def initialize(&block)
|
||||
@fde = true
|
||||
@pull = true
|
||||
|
||||
yield self if block_given?
|
||||
end
|
||||
|
||||
# Create an API instance using the current user creds. A new
|
||||
# instance is created any time `login` or `password` change.
|
||||
|
||||
def api
|
||||
@api ||= Octokit::Client.new :login => login, :password => password
|
||||
end
|
||||
|
||||
# Spew a bunch of debug logging? Default is `false`.
|
||||
|
||||
def debug?
|
||||
!!@debug
|
||||
end
|
||||
|
||||
attr_writer :debug
|
||||
|
||||
# A GitHub user's public email.
|
||||
|
||||
attr_accessor :email
|
||||
|
||||
# The shell script that loads Boxen's environment.
|
||||
|
||||
def envfile
|
||||
"#{homedir}/env.sh"
|
||||
end
|
||||
|
||||
# Is full disk encryption required? Default is `true`. Respects
|
||||
# the `BOXEN_NO_FDE` environment variable.
|
||||
|
||||
def fde?
|
||||
!ENV["BOXEN_NO_FDE"] && @fde
|
||||
end
|
||||
|
||||
attr_writer :fde
|
||||
|
||||
# Boxen's home directory. Default is `"/opt/boxen"`. Respects the
|
||||
# `BOXEN_HOME` environment variable.
|
||||
|
||||
def homedir
|
||||
@homedir || ENV["BOXEN_HOME"] || "/opt/boxen"
|
||||
end
|
||||
|
||||
attr_writer :homedir
|
||||
|
||||
# Boxen's log file. Default is `"/tmp/boxen.log"`. Respects the
|
||||
# `BOXEN_LOG_FILE` environment variable.
|
||||
|
||||
def logfile
|
||||
@logfile || ENV["BOXEN_LOG_FILE"] || "/tmp/boxen.log"
|
||||
end
|
||||
|
||||
attr_writer :logfile
|
||||
|
||||
# A GitHub user login. Default is `nil`.
|
||||
|
||||
attr_reader :login
|
||||
|
||||
def login=(login)
|
||||
@api = nil
|
||||
@login = login
|
||||
end
|
||||
|
||||
# Is Boxen running on the `master` branch?
|
||||
|
||||
def master?
|
||||
`git symbolic-ref HEAD`.chomp == "refs/heads/master"
|
||||
end
|
||||
|
||||
# A GitHub user's profile name.
|
||||
|
||||
attr_accessor :name
|
||||
|
||||
# A GitHub user password. Default is `nil`.
|
||||
|
||||
attr_reader :password
|
||||
|
||||
def password=(password)
|
||||
@api = nil
|
||||
@password = password
|
||||
end
|
||||
|
||||
# Just go through the motions? Default is `false`.
|
||||
|
||||
def pretend?
|
||||
!!@pretend
|
||||
end
|
||||
|
||||
attr_writer :pretend
|
||||
|
||||
# Run a profiler on Puppet? Default is `false`.
|
||||
|
||||
def profile?
|
||||
!!@profile
|
||||
end
|
||||
|
||||
attr_writer :profile
|
||||
|
||||
# Dirty tree?
|
||||
def dirty?
|
||||
changes.empty?
|
||||
end
|
||||
|
||||
def changes
|
||||
`git status --porcelain`.strip
|
||||
end
|
||||
|
||||
# An Array of Boxen::Project entries, one for each project Boxen
|
||||
# knows how to manage.
|
||||
#
|
||||
# FIX: Revisit this once we restructure template projects. It's
|
||||
# broken for several reasons: It assumes paths that won't be
|
||||
# right, and it assumes projects live in the same repo as this
|
||||
# file.
|
||||
|
||||
def projects
|
||||
root = File.expand_path "../../..", __FILE__
|
||||
files = Dir["modules/github/manifests/projects/*.pp"]
|
||||
names = (files.map { |m| File.basename m, ".pp" } - %w(all)).sort
|
||||
|
||||
names.map do |name|
|
||||
Boxen::Project.new "#{srcdir}/#{name}"
|
||||
end
|
||||
end
|
||||
|
||||
# The directory where repos live. Default is
|
||||
# `"/Users/#{user}/src"`.
|
||||
|
||||
def srcdir
|
||||
@srcdir || "/Users/#{user}/src"
|
||||
end
|
||||
|
||||
attr_writer :srcdir
|
||||
|
||||
# Don't auto-create issues on failure? Default is `false`.
|
||||
# Respects the `BOXEN_NO_ISSUE` environment variable.
|
||||
|
||||
def stealth?
|
||||
!!ENV["BOXEN_NO_ISSUE"] || @stealth
|
||||
end
|
||||
|
||||
attr_writer :stealth
|
||||
|
||||
# A local user login. Default is the `USER` environment variable.
|
||||
|
||||
def user
|
||||
@user || ENV["USER"]
|
||||
end
|
||||
|
||||
attr_writer :user
|
||||
end
|
||||
end
|
||||
139
test/boxen_config_test.rb
Normal file
139
test/boxen_config_test.rb
Normal file
@@ -0,0 +1,139 @@
|
||||
require "boxen/test"
|
||||
require "boxen/config"
|
||||
|
||||
class BoxenConfigTest < Boxen::Test
|
||||
def setup
|
||||
@config = Boxen::Config.new
|
||||
end
|
||||
|
||||
def test_debug?
|
||||
refute @config.debug?
|
||||
|
||||
@config.debug = true
|
||||
assert @config.debug?
|
||||
end
|
||||
|
||||
def test_email
|
||||
assert_nil @config.email
|
||||
|
||||
@config.email = "foo"
|
||||
assert_equal "foo", @config.email
|
||||
end
|
||||
|
||||
def test_fde?
|
||||
assert @config.fde?
|
||||
|
||||
@config.fde = false
|
||||
refute @config.fde?
|
||||
end
|
||||
|
||||
def test_fde_env_var
|
||||
ENV.expects(:[]).with("BOXEN_NO_FDE").returns "1"
|
||||
refute @config.fde?
|
||||
end
|
||||
|
||||
def test_homedir
|
||||
assert_equal "/opt/boxen", @config.homedir
|
||||
|
||||
@config.homedir = "foo"
|
||||
assert_equal "foo", @config.homedir
|
||||
end
|
||||
|
||||
def test_homedir_env_var_boxen_home
|
||||
ENV.expects(:[]).with("BOXEN_HOME").returns "foo"
|
||||
assert_equal "foo", @config.homedir
|
||||
end
|
||||
|
||||
def test_initialize
|
||||
config = Boxen::Config.new do |c|
|
||||
c.homedir = "foo"
|
||||
end
|
||||
|
||||
assert_equal "foo", config.homedir
|
||||
end
|
||||
|
||||
def test_logfile
|
||||
assert_equal "/tmp/boxen.log", @config.logfile
|
||||
|
||||
@config.logfile = "foo"
|
||||
assert_equal "foo", @config.logfile
|
||||
end
|
||||
|
||||
def test_logfile_env_var
|
||||
ENV.expects(:[]).with("BOXEN_LOG_FILE").returns "foo"
|
||||
assert_equal "foo", @config.logfile
|
||||
end
|
||||
|
||||
def test_login
|
||||
assert_nil @config.login
|
||||
|
||||
@config.login = "foo"
|
||||
assert_equal "foo", @config.login
|
||||
end
|
||||
|
||||
def test_name
|
||||
assert_nil @config.name
|
||||
|
||||
@config.name = "foo"
|
||||
assert_equal "foo", @config.name
|
||||
end
|
||||
|
||||
def test_password
|
||||
assert_nil @config.password
|
||||
|
||||
@config.password = "foo"
|
||||
assert_equal "foo", @config.password
|
||||
end
|
||||
|
||||
def test_pretend?
|
||||
refute @config.pretend?
|
||||
|
||||
@config.pretend = true
|
||||
assert @config.pretend?
|
||||
end
|
||||
|
||||
def test_profile?
|
||||
refute @config.profile?
|
||||
|
||||
@config.profile = true
|
||||
assert @config.profile?
|
||||
end
|
||||
|
||||
def test_projects
|
||||
root = File.expand_path "../..", __FILE__
|
||||
files = Dir["#{root}/modules/github/manifests/projects/*.pp"]
|
||||
|
||||
# all.pp is autogenerated
|
||||
files.reject! { |f| File.basename(f) == "all.pp" }
|
||||
|
||||
assert_equal files.size, @config.projects.size
|
||||
end
|
||||
|
||||
def test_srcdir
|
||||
@config.expects(:user).returns "foo"
|
||||
assert_equal "/Users/foo/src", @config.srcdir
|
||||
|
||||
@config.srcdir = "elsewhere"
|
||||
assert_equal "elsewhere", @config.srcdir
|
||||
end
|
||||
|
||||
def test_stealth?
|
||||
refute @config.stealth?
|
||||
|
||||
@config.stealth = true
|
||||
assert @config.stealth?
|
||||
end
|
||||
|
||||
def test_stealth_env_var
|
||||
ENV.expects(:[]).with("BOXEN_NO_ISSUE").returns "1"
|
||||
assert @config.stealth?
|
||||
end
|
||||
|
||||
def test_user
|
||||
ENV.expects(:[]).with("USER").returns "foo"
|
||||
assert_equal "foo", @config.user
|
||||
|
||||
@config.user = "bar"
|
||||
assert_equal "bar", @config.user
|
||||
end
|
||||
end
|
||||
10
test/system_timer.rb
Normal file
10
test/system_timer.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
# THIS IS SUCH HAX. Faraday helpfully reminds you to install
|
||||
# `system_timer` if you're running Ruby 1.8, since Timeout can give
|
||||
# unreliable results. We can't do this during first-time runs, since
|
||||
# there's no C compiler available.
|
||||
#
|
||||
# To squash the message and stop confusing people, this shim just
|
||||
# exposes Timeout as SystemTimer. I'm a bad person.
|
||||
|
||||
require "timeout"
|
||||
SystemTimer = Timeout
|
||||
Reference in New Issue
Block a user