dotum 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.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.groc.json +6 -0
- data/.rspec +4 -0
- data/.simplecov +5 -0
- data/.travis.yml +15 -0
- data/CONTRIBUTING.md +63 -0
- data/Gemfile +59 -0
- data/Guardfile +30 -0
- data/MIT-LICENSE.md +21 -0
- data/README.md +24 -0
- data/Rakefile +15 -0
- data/bin/dotum +7 -0
- data/data/default_rules.dotum +44 -0
- data/dotum.gemspec +19 -0
- data/extern/json/CHANGES.md +9 -0
- data/extern/json/COPYING +58 -0
- data/extern/json/README.rdoc +358 -0
- data/extern/json/lib/json.rb +62 -0
- data/extern/json/lib/json/.DS_Store +0 -0
- data/extern/json/lib/json/add/bigdecimal.rb +28 -0
- data/extern/json/lib/json/add/complex.rb +22 -0
- data/extern/json/lib/json/add/core.rb +11 -0
- data/extern/json/lib/json/add/date.rb +34 -0
- data/extern/json/lib/json/add/date_time.rb +50 -0
- data/extern/json/lib/json/add/exception.rb +31 -0
- data/extern/json/lib/json/add/ostruct.rb +31 -0
- data/extern/json/lib/json/add/range.rb +29 -0
- data/extern/json/lib/json/add/rational.rb +22 -0
- data/extern/json/lib/json/add/regexp.rb +30 -0
- data/extern/json/lib/json/add/struct.rb +30 -0
- data/extern/json/lib/json/add/symbol.rb +25 -0
- data/extern/json/lib/json/add/time.rb +38 -0
- data/extern/json/lib/json/common.rb +487 -0
- data/extern/json/lib/json/generic_object.rb +70 -0
- data/extern/json/lib/json/pure.rb +21 -0
- data/extern/json/lib/json/pure/generator.rb +522 -0
- data/extern/json/lib/json/pure/parser.rb +359 -0
- data/extern/json/lib/json/version.rb +8 -0
- data/lib/dotum.rb +11 -0
- data/lib/dotum/abstract_rules.rb +5 -0
- data/lib/dotum/abstract_rules/base.rb +56 -0
- data/lib/dotum/abstract_rules/globbable_files.rb +51 -0
- data/lib/dotum/abstract_rules/options_base.rb +33 -0
- data/lib/dotum/autoload_convention.rb +34 -0
- data/lib/dotum/cli.rb +35 -0
- data/lib/dotum/context.rb +55 -0
- data/lib/dotum/externs/json.rb +9 -0
- data/lib/dotum/logger.rb +50 -0
- data/lib/dotum/options_context.rb +21 -0
- data/lib/dotum/rule_dsl.rb +73 -0
- data/lib/dotum/rule_options_dsl.rb +116 -0
- data/lib/dotum/rule_runner.rb +16 -0
- data/lib/dotum/rules.rb +5 -0
- data/lib/dotum/rules/cd.rb +23 -0
- data/lib/dotum/rules/download.rb +32 -0
- data/lib/dotum/rules/link.rb +22 -0
- data/lib/dotum/rules/repo.rb +65 -0
- data/lib/dotum/rules/require_extension.rb +42 -0
- data/lib/dotum/rules/run.rb +23 -0
- data/lib/dotum/rules/use.rb +33 -0
- data/lib/dotum/rules/use_repo.rb +58 -0
- data/lib/dotum/standard_options.rb +5 -0
- data/lib/dotum/standard_options/destination.rb +22 -0
- data/lib/dotum/util.rb +5 -0
- data/lib/dotum/util/ansi_colors.rb +26 -0
- data/lib/dotum/util/path.rb +120 -0
- data/lib/dotum/version.rb +5 -0
- data/spec/fixtures/autoload_convention/abc_one_two_three.rb +7 -0
- data/spec/fixtures/autoload_convention/allcaps.rb +7 -0
- data/spec/fixtures/autoload_convention/mismatched.rb +3 -0
- data/spec/fixtures/autoload_convention/multi_token.rb +7 -0
- data/spec/fixtures/autoload_convention/single.rb +7 -0
- data/spec/fixtures/autoload_convention/string.rb +7 -0
- data/spec/spec_helper.rb +76 -0
- data/spec/unit/dotum/autoload_convention/const_missing_spec.rb +57 -0
- data/tasks/console.rake +9 -0
- data/tasks/spec.rake +7 -0
- data/tasks/spec/ci.rake +16 -0
- data/tasks/spec/coverage.rake +19 -0
- data/tasks/spec/mutate.rake +71 -0
- metadata +123 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class Dotum::AbstractRules::OptionsBase < Dotum::AbstractRules::Base
|
4
|
+
|
5
|
+
def self.exec(context, *args, &block)
|
6
|
+
options = option_defaults.merge(expand_shorthand(*args))
|
7
|
+
options.merge! eval_options_block(&block) if block
|
8
|
+
|
9
|
+
if errors = validate_options(options)
|
10
|
+
raise "Validation errors: #{errors.inspect}"
|
11
|
+
end
|
12
|
+
|
13
|
+
if respond_to? :expand_options
|
14
|
+
expand_options(context, options).map { |rule_options|
|
15
|
+
new(context, rule_options).exec
|
16
|
+
}
|
17
|
+
else
|
18
|
+
new(context, options).exec
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(context, options)
|
23
|
+
super(context)
|
24
|
+
|
25
|
+
options.each do |option, value|
|
26
|
+
filter = self.class.option_configs[option][:filter]
|
27
|
+
value = instance_exec(value, &filter) if filter && !value.nil?
|
28
|
+
|
29
|
+
instance_variable_set(:"@#{option}", value)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# Autoload Convention
|
4
|
+
# ===================
|
5
|
+
# We adhere to a strict convention for the constants in this library:
|
6
|
+
#
|
7
|
+
# `Camel::Caps::BasedConstants` map to their underscore variants of
|
8
|
+
# `camel/caps/based_constants`.
|
9
|
+
#
|
10
|
+
# Each autoloadable parent module/class only needs to to `extend` the
|
11
|
+
# `AutoloadConvention` to bootstrap this behavior.
|
12
|
+
module Dotum
|
13
|
+
module AutoloadConvention
|
14
|
+
|
15
|
+
# `autoload` is dead, and we don't want to deal with its removal in 2.0,
|
16
|
+
# so here's a thread-unsafe poor man's solution.
|
17
|
+
def const_missing(sym)
|
18
|
+
full_sym = "#{name}::#{sym}"
|
19
|
+
path_parts = full_sym.split("::").map { |part|
|
20
|
+
part.gsub! /([^A-Z])([A-Z]+)/, "\\1_\\2" # OneTwo -> One_Two
|
21
|
+
part.gsub! /([A-Z]+)([A-Z][^A-Z]+)/, "\\1_\\2" # ABCOne -> ABC_One
|
22
|
+
|
23
|
+
part.downcase
|
24
|
+
}
|
25
|
+
|
26
|
+
require File.join(path_parts)
|
27
|
+
|
28
|
+
# Make sure that we don't get stuck in an endless loop. `const_get` calls
|
29
|
+
# into `const_missing`, so we can't use that.
|
30
|
+
eval "defined?(#{full_sym}) ? #{full_sym} : super"
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
data/lib/dotum/cli.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class Dotum::CLI
|
4
|
+
|
5
|
+
def self.exec(args)
|
6
|
+
new(args).exec!
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(args)
|
10
|
+
@args = args
|
11
|
+
|
12
|
+
@state_dir = Dotum::Util::Path.new("~/.dotum")
|
13
|
+
@target_dir = Dotum::Util::Path.new("~")
|
14
|
+
@package_dir = Dotum::Util::Path.new("~/.dotum/local")
|
15
|
+
end
|
16
|
+
|
17
|
+
def exec!
|
18
|
+
context = Dotum::Context.new(
|
19
|
+
# :no_remote => true,
|
20
|
+
:state_dir => @state_dir,
|
21
|
+
:target_dir => @target_dir,
|
22
|
+
:logger => Dotum::Logger.new
|
23
|
+
)
|
24
|
+
|
25
|
+
unless @package_dir.directory?
|
26
|
+
puts
|
27
|
+
puts "#{@package_dir.pretty} doesn't exist! Creating for now..."
|
28
|
+
@package_dir.mkpath!
|
29
|
+
end
|
30
|
+
|
31
|
+
Dotum::Rules::UseRepo.exec(context, @package_dir)
|
32
|
+
print "\n\n"
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class Dotum::Context
|
4
|
+
|
5
|
+
def initialize(attributes={})
|
6
|
+
set_attributes(attributes)
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :package_dir
|
10
|
+
attr_reader :target_dir
|
11
|
+
attr_reader :state_dir
|
12
|
+
|
13
|
+
attr_reader :logger
|
14
|
+
attr_reader :depth
|
15
|
+
|
16
|
+
def no_remote?
|
17
|
+
@no_remote
|
18
|
+
end
|
19
|
+
|
20
|
+
def attributes
|
21
|
+
result = {}
|
22
|
+
instance_variables.each do |var_name|
|
23
|
+
result[var_name[1..-1].to_sym] = instance_variable_get(var_name)
|
24
|
+
end
|
25
|
+
|
26
|
+
result
|
27
|
+
end
|
28
|
+
|
29
|
+
def fork(new_attributes={})
|
30
|
+
self.class.new(attributes.merge(new_attributes || {}))
|
31
|
+
end
|
32
|
+
|
33
|
+
def child(new_attributes={})
|
34
|
+
new_attributes ||= {}
|
35
|
+
new_attributes[:depth] = (@depth || 0) + 1
|
36
|
+
|
37
|
+
fork(new_attributes)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def set_attributes(attributes)
|
43
|
+
attributes.each_pair do |key, value|
|
44
|
+
case key
|
45
|
+
when :package_dir then @package_dir = Dotum::Util::Path.new(value)
|
46
|
+
when :target_dir then @target_dir = Dotum::Util::Path.new(value)
|
47
|
+
when :state_dir then @state_dir = Dotum::Util::Path.new(value)
|
48
|
+
when :logger then @logger = value
|
49
|
+
when :no_remote then @no_remote = value
|
50
|
+
when :depth then @depth = value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
data/lib/dotum/logger.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class Dotum::Logger
|
4
|
+
include Dotum::Util::ANSIColors
|
5
|
+
|
6
|
+
INDENT = " "
|
7
|
+
|
8
|
+
def start_rule(rule)
|
9
|
+
@last_rule = rule
|
10
|
+
@last_rule_start = Time.now
|
11
|
+
|
12
|
+
print "\n"
|
13
|
+
print rule_line(rule)
|
14
|
+
end
|
15
|
+
|
16
|
+
def finish_rule(rule, status, reason)
|
17
|
+
message = "#{rule_line(rule)} - #{status.inspect} - #{reason.inspect}"
|
18
|
+
if @last_rule == rule
|
19
|
+
delta = (Time.now - @last_rule_start) * 1000.0
|
20
|
+
message += " (%.2fms)" % delta
|
21
|
+
|
22
|
+
print "\r"
|
23
|
+
else
|
24
|
+
print "\n\n"
|
25
|
+
end
|
26
|
+
|
27
|
+
print message
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def rule_line(rule)
|
33
|
+
indent = INDENT * rule.context.depth
|
34
|
+
action = rule.class.pretty
|
35
|
+
subject = rule.pretty_subject
|
36
|
+
|
37
|
+
action = c_cyan(action)
|
38
|
+
subject = colorize_subject(subject)
|
39
|
+
|
40
|
+
"#{indent}#{action}: #{subject}"
|
41
|
+
end
|
42
|
+
|
43
|
+
SUBJECT_MATCHER = /^(.*?)( \(.+\))?$/
|
44
|
+
def colorize_subject(subject)
|
45
|
+
match = SUBJECT_MATCHER.match(subject)
|
46
|
+
|
47
|
+
"#{c_magenta(match[1])}#{match[2]}"
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "set"
|
4
|
+
|
5
|
+
class Dotum::OptionsContext < Hash
|
6
|
+
|
7
|
+
def initialize(option_configs)
|
8
|
+
@known_options = Set.new(option_configs.keys)
|
9
|
+
end
|
10
|
+
|
11
|
+
def method_missing(sym, *args)
|
12
|
+
super if args.size != 1
|
13
|
+
|
14
|
+
unless @known_options.include? sym
|
15
|
+
raise ArgumentError, "Unknown option '#{sym}'"
|
16
|
+
end
|
17
|
+
|
18
|
+
self[sym] = args[0]
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "rbconfig"
|
4
|
+
|
5
|
+
module Dotum::RuleDSL
|
6
|
+
|
7
|
+
def success!(reason=nil)
|
8
|
+
throw :finish_rule, [:success, reason]
|
9
|
+
end
|
10
|
+
|
11
|
+
def failure!(reason=nil)
|
12
|
+
throw :finish_rule, [:failure, reason]
|
13
|
+
end
|
14
|
+
|
15
|
+
def skip!(reason=nil)
|
16
|
+
throw :finish_rule, [:skip, reason]
|
17
|
+
end
|
18
|
+
|
19
|
+
def platform?(name)
|
20
|
+
os = RbConfig::CONFIG["host_os"].downcase
|
21
|
+
|
22
|
+
case name
|
23
|
+
when /os\s?x/i then /mac|darwin/ === os
|
24
|
+
when /win(dows)?/i then /mswin|win|mingw/ === os
|
25
|
+
when /linux/i then /linux|cygwin/ === os
|
26
|
+
when /bsd/i then /bsd/ === os
|
27
|
+
when /solaris/i then /solaris|sunos/ === os
|
28
|
+
else
|
29
|
+
if name.is_a? Regexp
|
30
|
+
name === os
|
31
|
+
else
|
32
|
+
Regexp.new(name, "i") === os
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def available?(command)
|
38
|
+
# TODO: Windows friendly.
|
39
|
+
`which "#{command}"`
|
40
|
+
$?.success?
|
41
|
+
end
|
42
|
+
|
43
|
+
def package_dir
|
44
|
+
context.package_dir
|
45
|
+
end
|
46
|
+
|
47
|
+
def target_dir
|
48
|
+
context.target_dir
|
49
|
+
end
|
50
|
+
|
51
|
+
def state_dir
|
52
|
+
context.state_dir
|
53
|
+
end
|
54
|
+
|
55
|
+
def method_missing(sym, *args, &block)
|
56
|
+
rule_class_name = sym.to_s.split("_").map(&:capitalize).join.to_sym
|
57
|
+
|
58
|
+
begin
|
59
|
+
rule_class = Dotum::Rules.const_get(rule_class_name)
|
60
|
+
rescue LoadError
|
61
|
+
raise NoMethodError, "Unknown rule #{sym}. Tried to load Dotum::Rules::#{rule_class_name}: #{$!.message}"
|
62
|
+
end
|
63
|
+
|
64
|
+
Dotum::RuleDSL.module_eval <<-end_eval, __FILE__, __LINE__
|
65
|
+
def #{sym}(*args, &block)
|
66
|
+
Dotum::Rules::#{rule_class_name}.exec(context, *args, &block)
|
67
|
+
end
|
68
|
+
end_eval
|
69
|
+
|
70
|
+
send(sym, *args, &block)
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Dotum::RuleOptionsDSL
|
4
|
+
|
5
|
+
OptionConfig = Struct.new(:filter, :validator, :default)
|
6
|
+
|
7
|
+
|
8
|
+
# DSL
|
9
|
+
# ---
|
10
|
+
|
11
|
+
def shorthand(*args)
|
12
|
+
@shorthand_config ||= args
|
13
|
+
end
|
14
|
+
|
15
|
+
def required(option, &block)
|
16
|
+
(@option_configs ||= {})[option] = OptionConfig.new(
|
17
|
+
block,
|
18
|
+
proc { |v| "Option '#{option}' is required." if v.nil? }
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
def optional(option, default=nil, &block)
|
23
|
+
(@option_configs ||= {})[option] = OptionConfig.new(block, nil, default)
|
24
|
+
end
|
25
|
+
|
26
|
+
def standard(option)
|
27
|
+
option_module_name = option.to_s.split("_").map(&:capitalize).join.to_sym
|
28
|
+
|
29
|
+
begin
|
30
|
+
option_module = Dotum::StandardOptions.const_get(option_module_name)
|
31
|
+
rescue LoadError
|
32
|
+
raise "Unknown standard option '#{option}'. Tried to load Dotum::StandardOptions::#{option_module_name}: #{$!.message}"
|
33
|
+
end
|
34
|
+
|
35
|
+
module_configs = option_module.instance_variable_get(:@option_configs)
|
36
|
+
unless module_configs && module_configs[option]
|
37
|
+
raise "Dotum::StandardOptions::#{option_module_name} is misconfigured; expected it to define the option '#{option}'"
|
38
|
+
end
|
39
|
+
|
40
|
+
include option_module
|
41
|
+
end
|
42
|
+
|
43
|
+
def register_preprocessor(sym)
|
44
|
+
@preprocessors ||= []
|
45
|
+
@preprocessors.push(sym)
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
# Configuration Management
|
50
|
+
# ------------------------
|
51
|
+
|
52
|
+
def option_configs
|
53
|
+
@memoized_option_configs ||= ancestors.reverse_each.reduce({}) { |result, ancestor|
|
54
|
+
result.merge(ancestor.instance_variable_get(:@option_configs) || {})
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
def option_defaults
|
59
|
+
@memoized_option_defaults ||= {}.tap do |defaults|
|
60
|
+
option_configs.each do |option, config|
|
61
|
+
defaults[option] = config[:default] unless config[:default].nil?
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def preprocessor_methods
|
67
|
+
@memoized_preprocessor_methods ||= ancestors.map { |ancestor|
|
68
|
+
ancestor.instance_variable_get(:@preprocessors)
|
69
|
+
}.compact.flatten
|
70
|
+
end
|
71
|
+
|
72
|
+
def shorthand_config
|
73
|
+
return @shorthand_config if defined? @shorthand_config
|
74
|
+
return superclass.shorthand_config if superclass.respond_to? :shorthand_config
|
75
|
+
|
76
|
+
[]
|
77
|
+
end
|
78
|
+
|
79
|
+
def expand_shorthand(*args)
|
80
|
+
result = {}
|
81
|
+
shorthand_config.zip(args).each do |config, value|
|
82
|
+
case config
|
83
|
+
when Symbol then result[config] = value
|
84
|
+
when Hash
|
85
|
+
if value.is_a? Hash
|
86
|
+
result[config.keys.first] = value.keys.first
|
87
|
+
result[config.values.first] = value.values.first
|
88
|
+
else
|
89
|
+
result[config.keys.first] = value
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
result
|
95
|
+
end
|
96
|
+
|
97
|
+
def eval_options_block(&block)
|
98
|
+
options = Dotum::OptionsContext.new(option_configs)
|
99
|
+
options.instance_eval(&block)
|
100
|
+
|
101
|
+
options
|
102
|
+
end
|
103
|
+
|
104
|
+
def validate_options(options)
|
105
|
+
errors = []
|
106
|
+
option_configs.each do |option, config|
|
107
|
+
next unless validator = config[:validator]
|
108
|
+
next unless error = validator.call(options[option])
|
109
|
+
|
110
|
+
errors.push(error)
|
111
|
+
end
|
112
|
+
|
113
|
+
errors.size > 0 ? errors : nil
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class Dotum::RuleRunner
|
4
|
+
include Dotum::RuleDSL
|
5
|
+
|
6
|
+
def self.eval(context, *args, &block)
|
7
|
+
new(context).instance_eval(*args, &block)
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(context)
|
11
|
+
@context = context
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :context
|
15
|
+
|
16
|
+
end
|