spud 0.1.14 → 0.1.19
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/spud.rb +2 -187
- data/lib/spud/build_tools/build_tools.rb +13 -0
- data/lib/spud/build_tools/make/task.rb +27 -0
- data/lib/spud/build_tools/package.json/task.rb +47 -0
- data/lib/spud/build_tools/spud/block_param_info.rb +77 -0
- data/lib/spud/build_tools/spud/dsl/file.rb +23 -0
- data/lib/spud/build_tools/spud/dsl/task.rb +63 -0
- data/lib/spud/build_tools/spud/shell/command.rb +52 -0
- data/lib/spud/build_tools/spud/shell/result.rb +26 -0
- data/lib/spud/build_tools/spud/task.rb +125 -0
- data/lib/spud/build_tools/task.rb +33 -0
- data/lib/spud/cli/parser.rb +101 -0
- data/lib/spud/cli/results.rb +25 -0
- data/lib/{error.rb → spud/error.rb} +1 -0
- data/lib/spud/help.rb +23 -0
- data/lib/spud/lister.rb +86 -0
- data/lib/spud/options.rb +14 -0
- data/lib/spud/runtime.rb +104 -0
- data/lib/spud/task_arg.rb +51 -0
- data/lib/spud/task_args.rb +49 -0
- data/lib/spud/version.rb +3 -0
- metadata +48 -28
- data/lib/args.rb +0 -73
- data/lib/build_tools/build_rule.rb +0 -21
- data/lib/build_tools/build_tool.rb +0 -19
- data/lib/build_tools/build_tools.rb +0 -13
- data/lib/build_tools/make/make.rb +0 -33
- data/lib/build_tools/package.json/package.json.rb +0 -33
- data/lib/build_tools/spud/file_context.rb +0 -33
- data/lib/build_tools/spud/rule.rb +0 -121
- data/lib/build_tools/spud/rule_context.rb +0 -58
- data/lib/build_tools/spud/shell_error.rb +0 -7
- data/lib/build_tools/spud/spud.rb +0 -27
- data/lib/shell.rb +0 -25
- data/lib/version.rb +0 -3
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require 'open3'
|
3
|
+
require 'spud/build_tools/spud/shell/result'
|
4
|
+
|
5
|
+
module Spud
|
6
|
+
module BuildTools
|
7
|
+
module Spud
|
8
|
+
module Shell
|
9
|
+
class Command
|
10
|
+
attr_reader :result
|
11
|
+
|
12
|
+
# @param command [String]
|
13
|
+
# @param silent [Boolean]
|
14
|
+
# @param handle [IO]
|
15
|
+
def self.call(command, silent: false, handle: STDOUT)
|
16
|
+
cmd = new(command, silent: silent, handle: handle)
|
17
|
+
cmd.issue!
|
18
|
+
cmd.result
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param command [String]
|
22
|
+
# @param silent [Boolean]
|
23
|
+
# @param handle [IO]
|
24
|
+
def initialize(command, silent: false, handle: STDOUT)
|
25
|
+
@command = command
|
26
|
+
@silent = silent
|
27
|
+
@handle = handle
|
28
|
+
|
29
|
+
@result = nil
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [void]
|
33
|
+
def issue!
|
34
|
+
capturer = StringIO.new
|
35
|
+
|
36
|
+
Open3.popen2e(@command) do |_stdin, stdout, thread|
|
37
|
+
loop do
|
38
|
+
line = stdout.gets
|
39
|
+
break unless line
|
40
|
+
|
41
|
+
@handle.write line unless @silent
|
42
|
+
capturer.puts line
|
43
|
+
end
|
44
|
+
|
45
|
+
@result = Result.new(capturer.string, thread.value)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Spud
|
2
|
+
module BuildTools
|
3
|
+
module Spud
|
4
|
+
module Shell
|
5
|
+
class Result < String
|
6
|
+
attr_reader :status
|
7
|
+
|
8
|
+
# @param output [String]
|
9
|
+
# @param status [Process::Status]
|
10
|
+
def initialize(output, status)
|
11
|
+
super(output)
|
12
|
+
@status = status
|
13
|
+
end
|
14
|
+
|
15
|
+
def method_missing(symbol, *args)
|
16
|
+
status.respond_to?(symbol) ? status.send(symbol, *args) : super
|
17
|
+
end
|
18
|
+
|
19
|
+
def respond_to_missing?(symbol, *)
|
20
|
+
status.respond_to?(symbol) || super
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'spud/error'
|
2
|
+
require 'spud/task_args'
|
3
|
+
require 'spud/build_tools/task'
|
4
|
+
require 'spud/build_tools/spud/task'
|
5
|
+
require 'spud/build_tools/spud/dsl/file'
|
6
|
+
require 'spud/build_tools/spud/dsl/task'
|
7
|
+
|
8
|
+
module Spud
|
9
|
+
module BuildTools
|
10
|
+
module Spud
|
11
|
+
class Task < BuildTools::Task
|
12
|
+
# @return [void]
|
13
|
+
def self.mount!
|
14
|
+
Dir['**/Spudfile', '**/*.spud'].each do |filename|
|
15
|
+
@filename = filename
|
16
|
+
file_dsl.instance_eval(File.read(filename), filename)
|
17
|
+
end
|
18
|
+
|
19
|
+
@filename = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [Spud::DSL::File]
|
23
|
+
def self.file_dsl
|
24
|
+
@file_dsl ||= DSL::File.new
|
25
|
+
end
|
26
|
+
|
27
|
+
# @param task [String]
|
28
|
+
# @param block [Proc]
|
29
|
+
# @return [void]
|
30
|
+
def self.add_task(task, &block)
|
31
|
+
raise "task '#{task}' somehow created without filename" unless @filename
|
32
|
+
|
33
|
+
qualified_name = [qualified_prefix(@filename), task.to_s].join('.').gsub(/^\./, '')
|
34
|
+
new(name: qualified_name, filename: @filename, &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
# @param filename [String]
|
38
|
+
# @param task [String]
|
39
|
+
# @param positional [Array]
|
40
|
+
# @param named [Hash]
|
41
|
+
def self.invoke(filename, task, positional, named)
|
42
|
+
task = task.to_s
|
43
|
+
task_obj = task_for(filename, task)
|
44
|
+
if task_obj
|
45
|
+
Runtime.invoke(task_obj.name, positional, named)
|
46
|
+
else
|
47
|
+
Runtime.invoke(task, positional, named)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# @param filename [String]
|
52
|
+
# @param task [String]
|
53
|
+
def self.task_for(filename, task)
|
54
|
+
task = task.to_s
|
55
|
+
if task.include?('.')
|
56
|
+
Runtime.tasks[task]
|
57
|
+
else
|
58
|
+
Runtime.tasks[[qualified_prefix(filename), task.to_s].join('.').gsub(/^\./, '')]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# @param filename [String]
|
63
|
+
# @return [String]
|
64
|
+
def self.qualified_prefix(filename)
|
65
|
+
dirname = File.dirname(filename)
|
66
|
+
dirname = '' if dirname == '.'
|
67
|
+
|
68
|
+
basename = File.basename(filename, '.spud')
|
69
|
+
basename_array = basename == 'Spudfile' ? [] : [basename]
|
70
|
+
|
71
|
+
(dirname.split('/') + basename_array).join('.')
|
72
|
+
end
|
73
|
+
|
74
|
+
def initialize(name:, filename:, &block)
|
75
|
+
super
|
76
|
+
@block = block
|
77
|
+
end
|
78
|
+
|
79
|
+
# @param positional [Array]
|
80
|
+
# @param named [Hash]
|
81
|
+
# @return [Object]
|
82
|
+
def invoke(positional, named)
|
83
|
+
check_required!(positional)
|
84
|
+
|
85
|
+
return task_dsl.instance_exec(*positional, &@block) unless args.any_named?
|
86
|
+
|
87
|
+
task_dsl.instance_exec(*positional, **symbolize_keys(named), &@block)
|
88
|
+
rescue ArgumentError => error
|
89
|
+
raise Error, "invocation of '#{name}' with #{error.message}"
|
90
|
+
end
|
91
|
+
|
92
|
+
# @return [Spud::TaskArgs]
|
93
|
+
def args
|
94
|
+
@args ||= ::Spud::TaskArgs.from_block(filename, &@block)
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
# @param positional [Array<String>]
|
100
|
+
# @return [void]
|
101
|
+
def check_required!(positional)
|
102
|
+
required_positional = args.required_positional
|
103
|
+
missing_positional = required_positional.length - positional.length
|
104
|
+
if missing_positional > 0
|
105
|
+
arguments = required_positional.length - missing_positional > 1 ? 'arguments' : 'argument'
|
106
|
+
raise Error, "invocation of '#{name}' missing required #{arguments} #{required_positional.join(', ')}"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# @return [Spud::DSL::Task]
|
111
|
+
def task_dsl
|
112
|
+
@task_dsl ||= DSL::Task.new(filename)
|
113
|
+
end
|
114
|
+
|
115
|
+
# @param hash [Hash]
|
116
|
+
# @return [Hash]
|
117
|
+
def symbolize_keys(hash)
|
118
|
+
hash.each_with_object({}) do |(key, value), new_hash|
|
119
|
+
new_hash[key.is_a?(String) ? key.to_sym : key] = value
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Spud
|
2
|
+
module BuildTools
|
3
|
+
class Task
|
4
|
+
# @return [String]
|
5
|
+
attr_reader :name
|
6
|
+
# @return [String]
|
7
|
+
attr_reader :filename
|
8
|
+
# @return [Spud::TaskArgs]
|
9
|
+
attr_reader :args
|
10
|
+
|
11
|
+
# @return [void]
|
12
|
+
def self.mount!
|
13
|
+
raise NotImplementedError
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param name [String]
|
17
|
+
# @param filename [String]
|
18
|
+
def initialize(name:, filename:)
|
19
|
+
@name = name
|
20
|
+
@filename = filename
|
21
|
+
|
22
|
+
Runtime.tasks[name.to_s] = self
|
23
|
+
end
|
24
|
+
|
25
|
+
# @param positional [Array]
|
26
|
+
# @param named [Hash]
|
27
|
+
# @return [Object]
|
28
|
+
def invoke(positional = [], named = {})
|
29
|
+
raise NotImplementedError
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'spud/cli/results'
|
2
|
+
|
3
|
+
module Spud
|
4
|
+
module CLI
|
5
|
+
class Parser
|
6
|
+
# @return [Spud::CLI::Results]
|
7
|
+
attr_reader :results
|
8
|
+
|
9
|
+
# @return [void]
|
10
|
+
def self.parse!
|
11
|
+
parse(ARGV)
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param args [Array<String>]
|
15
|
+
# @return [Spud::CLI::Results]
|
16
|
+
def self.parse(args)
|
17
|
+
new(args).parse!
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param args [Array<String>]
|
21
|
+
def initialize(args)
|
22
|
+
@args = args.dup
|
23
|
+
@results = Results.new
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [void]
|
27
|
+
def parse!
|
28
|
+
parse_arg! until done?
|
29
|
+
results
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# @return [void]
|
35
|
+
def parse_arg!
|
36
|
+
if before_task_name?
|
37
|
+
flag? ? handle_option! : set_task_name!
|
38
|
+
else
|
39
|
+
if flag?
|
40
|
+
results.named[lstrip_hyphens(take!)] = take!
|
41
|
+
else
|
42
|
+
results.positional << take!
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# @return [void]
|
48
|
+
def handle_option!
|
49
|
+
flag = take!
|
50
|
+
case flag
|
51
|
+
when '-h', '--help' then options.help = true
|
52
|
+
when '-f', '--files' then options.files = true
|
53
|
+
when '-w', '--watch' then options.watches << take!
|
54
|
+
when '--debug' then options.debug = true
|
55
|
+
else raise Error, "invalid option: '#{flag}'"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# @return [Spud::Options]
|
60
|
+
def options
|
61
|
+
results.options
|
62
|
+
end
|
63
|
+
|
64
|
+
# @param flag [String]
|
65
|
+
# @return [String]
|
66
|
+
def lstrip_hyphens(flag)
|
67
|
+
flag.gsub(/^-+/, '')
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [Boolean]
|
71
|
+
def before_task_name?
|
72
|
+
!results.task
|
73
|
+
end
|
74
|
+
|
75
|
+
# @return [void]
|
76
|
+
def set_task_name!
|
77
|
+
results.task = take!
|
78
|
+
end
|
79
|
+
|
80
|
+
# @return [String]
|
81
|
+
def take!
|
82
|
+
@args.shift
|
83
|
+
end
|
84
|
+
|
85
|
+
# @return [String]
|
86
|
+
def arg
|
87
|
+
@args.first
|
88
|
+
end
|
89
|
+
|
90
|
+
# @return [Boolean]
|
91
|
+
def flag?
|
92
|
+
arg.start_with?('-')
|
93
|
+
end
|
94
|
+
|
95
|
+
# @return [Boolean]
|
96
|
+
def done?
|
97
|
+
@args.empty?
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spud/options'
|
2
|
+
|
3
|
+
module Spud
|
4
|
+
module CLI
|
5
|
+
class Results
|
6
|
+
# @return [String]
|
7
|
+
attr_accessor :task
|
8
|
+
|
9
|
+
# @return [Spud::Options]
|
10
|
+
def options
|
11
|
+
@options ||= Options.new
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [Array<String>]
|
15
|
+
def positional
|
16
|
+
@positional ||= []
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [Hash{String->String}]
|
20
|
+
def named
|
21
|
+
@named ||= {}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/spud/help.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require 'spud/version'
|
3
|
+
|
4
|
+
module Spud
|
5
|
+
module Help
|
6
|
+
# @return [void]
|
7
|
+
def self.print!
|
8
|
+
help = StringIO.new
|
9
|
+
|
10
|
+
help.puts "spud #{VERSION}"
|
11
|
+
help.puts
|
12
|
+
help.puts 'usage:'
|
13
|
+
help.puts ' spud [options] <task> [args]'
|
14
|
+
help.puts
|
15
|
+
help.puts 'options:'
|
16
|
+
help.puts ' -h, --help show this help dialog'
|
17
|
+
help.puts ' -f, --files list parsed files'
|
18
|
+
help.puts ' --debug run in debug mode'
|
19
|
+
|
20
|
+
puts help.string
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/spud/lister.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
module Spud
|
4
|
+
class Lister
|
5
|
+
# @param tasks [Array<BuildTools::Task>]
|
6
|
+
def initialize(tasks)
|
7
|
+
@tasks = tasks
|
8
|
+
end
|
9
|
+
|
10
|
+
# @return [void]
|
11
|
+
def list!
|
12
|
+
builder = StringIO.new
|
13
|
+
|
14
|
+
@tasks.each do |task|
|
15
|
+
builder.write task.name.ljust(max_task_length)
|
16
|
+
|
17
|
+
if show_positional_args?
|
18
|
+
builder.write ' '
|
19
|
+
builder.write task.args.positional.join(' ').ljust(max_positional_string_length)
|
20
|
+
end
|
21
|
+
|
22
|
+
if show_named_args?
|
23
|
+
builder.write ' '
|
24
|
+
builder.write task.args.named.join(' ').ljust(max_named_string_length)
|
25
|
+
end
|
26
|
+
|
27
|
+
if show_filenames?
|
28
|
+
builder.write ' '
|
29
|
+
builder.write task.filename
|
30
|
+
end
|
31
|
+
|
32
|
+
builder.write "\n"
|
33
|
+
end
|
34
|
+
|
35
|
+
puts builder.string
|
36
|
+
end
|
37
|
+
|
38
|
+
# @return [void]
|
39
|
+
def list_filenames!
|
40
|
+
puts filenames.join("\n")
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
# @return [Integer]
|
46
|
+
def max_task_length
|
47
|
+
@max_task_length ||= @tasks.map { |task| task.name.length }.max
|
48
|
+
end
|
49
|
+
|
50
|
+
# @return [Integer]
|
51
|
+
def max_positional_string_length
|
52
|
+
@max_positional_string_length ||= @tasks
|
53
|
+
.map { |task| task.args.positional.join(' ') }
|
54
|
+
.map(&:length)
|
55
|
+
.max
|
56
|
+
end
|
57
|
+
|
58
|
+
# @return [Boolean]
|
59
|
+
def show_positional_args?
|
60
|
+
@show_positional_args ||= @tasks.any? { |task| task.args.any_positional? }
|
61
|
+
end
|
62
|
+
|
63
|
+
# @return [Integer]
|
64
|
+
def max_named_string_length
|
65
|
+
@max_named_string_length ||= @tasks
|
66
|
+
.map { |task| task.args.named.join(' ') }
|
67
|
+
.map(&:length)
|
68
|
+
.max
|
69
|
+
end
|
70
|
+
|
71
|
+
# @return [Boolean]
|
72
|
+
def show_named_args?
|
73
|
+
@show_named_args ||= @tasks.any? { |task| task.args.any_named? }
|
74
|
+
end
|
75
|
+
|
76
|
+
# @return [Array<String>]
|
77
|
+
def filenames
|
78
|
+
@filenames ||= @tasks.map(&:filename).uniq
|
79
|
+
end
|
80
|
+
|
81
|
+
# @return [Boolean]
|
82
|
+
def show_filenames?
|
83
|
+
filenames.length > 1
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|