spud 0.2.3 → 0.2.4
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 +3 -2
- data/lib/spud/block_param_info.rb +80 -0
- data/lib/spud/cli/options.rb +35 -0
- data/lib/spud/cli/parser.rb +22 -19
- data/lib/spud/cli/results.rb +18 -11
- data/lib/spud/driver.rb +134 -0
- data/lib/spud/error.rb +1 -0
- data/lib/spud/help.rb +13 -14
- data/lib/spud/lister.rb +27 -22
- data/lib/spud/task_arg.rb +15 -12
- data/lib/spud/task_args.rb +20 -18
- data/lib/spud/task_runners/make/task.rb +66 -0
- data/lib/spud/task_runners/package.json/task.rb +70 -0
- data/lib/spud/{build_tools/spud → task_runners/spud_task_runner}/dependency.rb +3 -2
- data/lib/spud/task_runners/spud_task_runner/file_dsl.rb +56 -0
- data/lib/spud/task_runners/spud_task_runner/shell/command.rb +58 -0
- data/lib/spud/{build_tools/spud → task_runners/spud_task_runner}/shell/result.rb +9 -4
- data/lib/spud/task_runners/spud_task_runner/task.rb +143 -0
- data/lib/spud/task_runners/spud_task_runner/task_dsl.rb +82 -0
- data/lib/spud/task_runners/task.rb +43 -0
- data/lib/spud/task_runners/task_runners.rb +25 -0
- data/lib/spud/version.rb +2 -1
- data/lib/spud/watch.rb +73 -0
- metadata +46 -17
- data/lib/spud/build_tools/build_tools.rb +0 -13
- data/lib/spud/build_tools/make/task.rb +0 -27
- data/lib/spud/build_tools/package.json/task.rb +0 -47
- data/lib/spud/build_tools/spud/block_param_info.rb +0 -77
- data/lib/spud/build_tools/spud/dsl/file.rb +0 -23
- data/lib/spud/build_tools/spud/dsl/task.rb +0 -63
- data/lib/spud/build_tools/spud/shell/command.rb +0 -52
- data/lib/spud/build_tools/spud/task.rb +0 -177
- data/lib/spud/build_tools/task.rb +0 -41
- data/lib/spud/options.rb +0 -14
- data/lib/spud/runtime.rb +0 -114
@@ -1,27 +0,0 @@
|
|
1
|
-
require 'spud/build_tools/task'
|
2
|
-
|
3
|
-
module Spud
|
4
|
-
module BuildTools
|
5
|
-
module Make
|
6
|
-
class Task < BuildTools::Task
|
7
|
-
def self.mount!
|
8
|
-
return unless File.exist?('Makefile')
|
9
|
-
|
10
|
-
if `command -v make`.empty?
|
11
|
-
puts 'Makefile detected, but no installation of `make` exists. Skipping make...'
|
12
|
-
return
|
13
|
-
end
|
14
|
-
|
15
|
-
source = File.read('Makefile')
|
16
|
-
source.scan(/^(\S+):.*/).map(&:first).each do |name|
|
17
|
-
new(name: name, filename: 'Makefile')
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def invoke(*)
|
22
|
-
system('make', name)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,47 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
require 'spud/build_tools/task'
|
3
|
-
|
4
|
-
module Spud
|
5
|
-
module BuildTools
|
6
|
-
module PackageJSON
|
7
|
-
class Task < BuildTools::Task
|
8
|
-
def self.mount!
|
9
|
-
return unless File.exist?('package.json')
|
10
|
-
|
11
|
-
opening_commands = %w[npm run]
|
12
|
-
if File.exist?('package.lock')
|
13
|
-
if `command -v npm`.empty?
|
14
|
-
puts 'package.json detected, but no installation of `npm` exists. Skipping npm...'
|
15
|
-
return
|
16
|
-
end
|
17
|
-
elsif File.exist?('yarn.lock')
|
18
|
-
if `command -v yarn`.empty?
|
19
|
-
puts 'package.json detected, but no installation of `yarn` exists. Skipping yarn...'
|
20
|
-
return
|
21
|
-
else
|
22
|
-
opening_commands = %w[yarn run]
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
source = File.read('package.json')
|
27
|
-
json = JSON.parse(source)
|
28
|
-
scripts = json['scripts']
|
29
|
-
return unless scripts
|
30
|
-
|
31
|
-
scripts.keys.each do |name|
|
32
|
-
new(name: name, filename: 'package.json', opening_commands: opening_commands)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def initialize(name:, filename:, opening_commands:)
|
37
|
-
super(name: name, filename: filename)
|
38
|
-
@opening_commands = opening_commands
|
39
|
-
end
|
40
|
-
|
41
|
-
def invoke(*)
|
42
|
-
system(*(@opening_commands + [name]))
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
@@ -1,77 +0,0 @@
|
|
1
|
-
require 'spud/task_arg'
|
2
|
-
|
3
|
-
module Spud
|
4
|
-
module BuildTools
|
5
|
-
module Spud
|
6
|
-
class BlockParamInfo
|
7
|
-
# @param filename [String]
|
8
|
-
# @param block [Proc]
|
9
|
-
def initialize(filename, &block)
|
10
|
-
@filename = filename
|
11
|
-
@block = block
|
12
|
-
end
|
13
|
-
|
14
|
-
# @return [Array<Spud::TaskArg>]
|
15
|
-
def task_args
|
16
|
-
parameters.map do |type, name|
|
17
|
-
case type
|
18
|
-
when :req
|
19
|
-
TaskArg.new(name, 'positional')
|
20
|
-
when :opt
|
21
|
-
TaskArg.new(name, 'positional', default: arg_values[name])
|
22
|
-
when :keyreq
|
23
|
-
TaskArg.new(name, 'named')
|
24
|
-
when :key
|
25
|
-
TaskArg.new(name, 'named', default: arg_values[name])
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
# @return [Array]
|
31
|
-
def dummy_args
|
32
|
-
[dummy_positional_args, dummy_named_args]
|
33
|
-
end
|
34
|
-
|
35
|
-
# @return [Array<NilClass>]
|
36
|
-
def dummy_positional_args
|
37
|
-
Array.new(parameters.count { |p| p.first == :req })
|
38
|
-
end
|
39
|
-
|
40
|
-
# @return [Hash{Symbol->NilClass}]
|
41
|
-
def dummy_named_args
|
42
|
-
parameters.select { |p| p.first == :keyreq }.map(&:last).each_with_object({}) { |n, h| h[n] = nil }
|
43
|
-
end
|
44
|
-
|
45
|
-
# @return [String]
|
46
|
-
def arg_hash_string
|
47
|
-
"{ #{parameters.map(&:last).map { |n| "#{n}: #{n}" }.join(', ')} }"
|
48
|
-
end
|
49
|
-
|
50
|
-
# @return [Hash]
|
51
|
-
def arg_values
|
52
|
-
@arg_values ||= begin
|
53
|
-
positional, named = dummy_args
|
54
|
-
lambda(arg_hash_string).call(*positional, **named)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
# @return [Array<Array<Symbol>>]
|
59
|
-
def parameters
|
60
|
-
@parameters ||= lambda.parameters
|
61
|
-
end
|
62
|
-
|
63
|
-
# @return [Proc]
|
64
|
-
def lambda(body = nil)
|
65
|
-
line = File.read(@filename).split("\n")[@block.source_location.last - 1]
|
66
|
-
|
67
|
-
match = /(do|{)\s*\|(?<params>[^|]+)\|/.match(line)
|
68
|
-
return -> {} unless match
|
69
|
-
|
70
|
-
param_source = match[:params]
|
71
|
-
param_source += ', _: nil, __: nil, ___: nil' if body
|
72
|
-
eval "-> (#{param_source}) { #{body} }"
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
require 'spud/build_tools/spud/task'
|
2
|
-
|
3
|
-
module Spud
|
4
|
-
module BuildTools
|
5
|
-
module Spud
|
6
|
-
module DSL
|
7
|
-
class File
|
8
|
-
def require_relative(name)
|
9
|
-
require("./#{name}")
|
10
|
-
end
|
11
|
-
|
12
|
-
def task(name, dependencies = {}, &block)
|
13
|
-
BuildTools::Spud::Task.add_task(name, dependencies, &block)
|
14
|
-
end
|
15
|
-
|
16
|
-
def method_missing(name, *args, &block)
|
17
|
-
task(name, *args, &block)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,63 +0,0 @@
|
|
1
|
-
require 'spud/error'
|
2
|
-
require 'spud/build_tools/spud/task'
|
3
|
-
require 'spud/build_tools/spud/shell/command'
|
4
|
-
|
5
|
-
module Spud
|
6
|
-
module BuildTools
|
7
|
-
module Spud
|
8
|
-
module DSL
|
9
|
-
class Task
|
10
|
-
def initialize(filename)
|
11
|
-
@filename = filename
|
12
|
-
end
|
13
|
-
|
14
|
-
def sh(command)
|
15
|
-
puts command
|
16
|
-
Shell::Command.(command)
|
17
|
-
end
|
18
|
-
|
19
|
-
def shh(command)
|
20
|
-
Shell::Command.(command)
|
21
|
-
end
|
22
|
-
|
23
|
-
def shhh(command)
|
24
|
-
Shell::Command.(command, silent: true)
|
25
|
-
end
|
26
|
-
|
27
|
-
def sh!(command)
|
28
|
-
puts command
|
29
|
-
result = Shell::Command.(command)
|
30
|
-
raise Error, "sh failed for '#{command}'" unless result.success?
|
31
|
-
result
|
32
|
-
end
|
33
|
-
|
34
|
-
def shh!(command)
|
35
|
-
result = Shell::Command.(command)
|
36
|
-
raise Error, "sh failed for '#{command}'" unless result.success?
|
37
|
-
result
|
38
|
-
end
|
39
|
-
|
40
|
-
def shhh!(command)
|
41
|
-
result = Shell::Command.(command, silent: true)
|
42
|
-
raise Error, "sh failed for '#{command}'" unless result.success?
|
43
|
-
result
|
44
|
-
end
|
45
|
-
|
46
|
-
def invoke(task, *positional, **named)
|
47
|
-
Spud::Task.invoke(@filename, task, positional, named)
|
48
|
-
rescue Error => error
|
49
|
-
puts "invoke failed for '#{task}': #{error}"
|
50
|
-
end
|
51
|
-
|
52
|
-
def invoke!(task, *positional, **named)
|
53
|
-
Spud::Task.invoke(@filename, task, positional, named)
|
54
|
-
end
|
55
|
-
|
56
|
-
def method_missing(symbol, *positional, **named)
|
57
|
-
Spud::Task.task_for(@filename, symbol) ? Spud::Task.invoke(@filename, symbol, positional, named) : super
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
@@ -1,52 +0,0 @@
|
|
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
|
@@ -1,177 +0,0 @@
|
|
1
|
-
require 'stringio'
|
2
|
-
require 'spud/error'
|
3
|
-
require 'spud/task_args'
|
4
|
-
require 'spud/build_tools/task'
|
5
|
-
require 'spud/build_tools/spud/dependency'
|
6
|
-
require 'spud/build_tools/spud/task'
|
7
|
-
require 'spud/build_tools/spud/dsl/file'
|
8
|
-
require 'spud/build_tools/spud/dsl/task'
|
9
|
-
|
10
|
-
module Spud
|
11
|
-
module BuildTools
|
12
|
-
module Spud
|
13
|
-
class Task < BuildTools::Task
|
14
|
-
# @return [void]
|
15
|
-
def self.mount!
|
16
|
-
Dir['**/Spudfile', '**/*.spud'].each do |filename|
|
17
|
-
@filename = filename
|
18
|
-
file_dsl.instance_eval(File.read(filename), filename)
|
19
|
-
end
|
20
|
-
|
21
|
-
@filename = nil
|
22
|
-
end
|
23
|
-
|
24
|
-
# @return [Spud::DSL::File]
|
25
|
-
def self.file_dsl
|
26
|
-
@file_dsl ||= DSL::File.new
|
27
|
-
end
|
28
|
-
|
29
|
-
# @param task [String]
|
30
|
-
# @param block [Proc]
|
31
|
-
# @return [void]
|
32
|
-
def self.add_task(task, dependencies, &block)
|
33
|
-
new(
|
34
|
-
name: qualified_name(@filename, task.to_s),
|
35
|
-
filename: @filename,
|
36
|
-
dependencies: dependencies,
|
37
|
-
&block
|
38
|
-
)
|
39
|
-
end
|
40
|
-
|
41
|
-
# @param filename [String]
|
42
|
-
# @param task [String]
|
43
|
-
# @param positional [Array]
|
44
|
-
# @param named [Hash]
|
45
|
-
def self.invoke(filename, task, positional, named)
|
46
|
-
task = task.to_s
|
47
|
-
task_obj = task_for(filename, task)
|
48
|
-
if task_obj
|
49
|
-
Runtime.invoke(task_obj.name, positional, named)
|
50
|
-
else
|
51
|
-
Runtime.invoke(task, positional, named)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
# @param filename [String]
|
56
|
-
# @param task [String]
|
57
|
-
# @return [BuildTools::Spud::Task]
|
58
|
-
def self.task_for(filename, task)
|
59
|
-
Runtime.tasks[qualified_name(filename, task.to_s)]
|
60
|
-
end
|
61
|
-
|
62
|
-
# @param filename [String]
|
63
|
-
# @param task [String]
|
64
|
-
# @return [String]
|
65
|
-
def self.qualified_name(filename, task)
|
66
|
-
raise "task '#{task}' somehow created without filename" unless filename
|
67
|
-
|
68
|
-
[qualified_prefix(filename), task.to_s].join('.').gsub(/^\./, '')
|
69
|
-
end
|
70
|
-
|
71
|
-
# @param filename [String]
|
72
|
-
# @return [String]
|
73
|
-
def self.qualified_prefix(filename)
|
74
|
-
dirname = File.dirname(filename)
|
75
|
-
dirname = '' if dirname == '.'
|
76
|
-
|
77
|
-
basename = File.basename(filename, '.spud')
|
78
|
-
basename_array = basename == 'Spudfile' ? [] : [basename]
|
79
|
-
|
80
|
-
(dirname.split('/') + basename_array).join('.')
|
81
|
-
end
|
82
|
-
|
83
|
-
# @param name [String]
|
84
|
-
# @param filename [String]
|
85
|
-
# @param dependencies [Hash]
|
86
|
-
# @param block [Proc]
|
87
|
-
def initialize(name:, filename:, dependencies:, &block)
|
88
|
-
super(name: name, filename: filename)
|
89
|
-
@dependencies = dependencies.map { |to, from| Dependency.new(to, from) }
|
90
|
-
@block = block
|
91
|
-
end
|
92
|
-
|
93
|
-
# @param positional [Array]
|
94
|
-
# @param named [Hash]
|
95
|
-
# @return [Object]
|
96
|
-
def invoke(positional, named)
|
97
|
-
if up_to_date?
|
98
|
-
puts "'#{name}' up to date"
|
99
|
-
return
|
100
|
-
end
|
101
|
-
|
102
|
-
check_required_args!(positional)
|
103
|
-
|
104
|
-
return task_dsl.instance_exec(*positional, &@block) unless args.any_named?
|
105
|
-
|
106
|
-
task_dsl.instance_exec(*positional, **symbolize_keys(named), &@block)
|
107
|
-
rescue ArgumentError => error
|
108
|
-
raise Error, "invocation of '#{name}' with #{error.message}"
|
109
|
-
end
|
110
|
-
|
111
|
-
# @return [Spud::TaskArgs]
|
112
|
-
def args
|
113
|
-
@args ||= ::Spud::TaskArgs.from_block(filename, &@block)
|
114
|
-
end
|
115
|
-
|
116
|
-
# @return [String]
|
117
|
-
def details
|
118
|
-
filename, line_cursor = @block.source_location
|
119
|
-
line_cursor -= 1
|
120
|
-
|
121
|
-
lines = File.read(filename).split("\n")
|
122
|
-
builder = StringIO.new
|
123
|
-
|
124
|
-
while lines[line_cursor - 1] && lines[line_cursor - 1].start_with?('#')
|
125
|
-
line_cursor -= 1
|
126
|
-
end
|
127
|
-
|
128
|
-
while lines[line_cursor].start_with?('#')
|
129
|
-
builder.puts lines[line_cursor]
|
130
|
-
line_cursor += 1
|
131
|
-
end
|
132
|
-
|
133
|
-
until lines[line_cursor].start_with?('end')
|
134
|
-
builder.puts lines[line_cursor]
|
135
|
-
line_cursor += 1
|
136
|
-
end
|
137
|
-
|
138
|
-
builder.puts lines[line_cursor]
|
139
|
-
builder.string
|
140
|
-
end
|
141
|
-
|
142
|
-
private
|
143
|
-
|
144
|
-
# @param positional [Array<String>]
|
145
|
-
# @return [void]
|
146
|
-
def check_required_args!(positional)
|
147
|
-
required_positional = args.required_positional
|
148
|
-
missing_positional = required_positional.length - positional.length
|
149
|
-
if missing_positional > 0
|
150
|
-
arguments = required_positional.length - missing_positional > 1 ? 'arguments' : 'argument'
|
151
|
-
raise Error, "invocation of '#{name}' missing required #{arguments} #{required_positional.join(', ')}"
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
# @return [Boolean]
|
156
|
-
def up_to_date?
|
157
|
-
return false if @dependencies.empty?
|
158
|
-
|
159
|
-
@dependencies.all?(&:up_to_date?)
|
160
|
-
end
|
161
|
-
|
162
|
-
# @return [Spud::DSL::Task]
|
163
|
-
def task_dsl
|
164
|
-
@task_dsl ||= DSL::Task.new(filename)
|
165
|
-
end
|
166
|
-
|
167
|
-
# @param hash [Hash]
|
168
|
-
# @return [Hash]
|
169
|
-
def symbolize_keys(hash)
|
170
|
-
hash.each_with_object({}) do |(key, value), new_hash|
|
171
|
-
new_hash[key.is_a?(String) ? key.to_sym : key] = value
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|