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
data/lib/spud/lister.rb
CHANGED
@@ -1,22 +1,27 @@
|
|
1
|
+
# typed: true
|
2
|
+
require 'sorbet-runtime'
|
1
3
|
require 'stringio'
|
4
|
+
require 'spud/task_runners/task'
|
2
5
|
|
3
6
|
module Spud
|
4
7
|
class Lister
|
5
|
-
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
sig {params(tasks: T::Array[TaskRunners::Task]).void}
|
6
11
|
def initialize(tasks)
|
7
12
|
@tasks = tasks
|
8
13
|
end
|
9
14
|
|
10
|
-
|
11
|
-
def
|
15
|
+
sig {void}
|
16
|
+
def list_tasks!
|
12
17
|
builder = StringIO.new
|
13
18
|
|
14
19
|
@tasks.each do |task|
|
15
20
|
builder.write task.name.ljust(max_task_length)
|
16
21
|
|
17
|
-
if
|
22
|
+
if show_ordered_args?
|
18
23
|
builder.write ' '
|
19
|
-
builder.write task.args.
|
24
|
+
builder.write task.args.ordered.join(' ').ljust(max_ordered_string_length)
|
20
25
|
end
|
21
26
|
|
22
27
|
if show_named_args?
|
@@ -35,32 +40,37 @@ module Spud
|
|
35
40
|
puts builder.string
|
36
41
|
end
|
37
42
|
|
38
|
-
|
43
|
+
sig {void}
|
39
44
|
def list_filenames!
|
40
45
|
puts filenames.join("\n")
|
41
46
|
end
|
42
47
|
|
48
|
+
sig {returns(T::Array[String])}
|
49
|
+
def filenames
|
50
|
+
@filenames ||= @tasks.map(&:filename).uniq
|
51
|
+
end
|
52
|
+
|
43
53
|
private
|
44
54
|
|
45
|
-
|
55
|
+
sig {returns(Integer)}
|
46
56
|
def max_task_length
|
47
57
|
@max_task_length ||= @tasks.map { |task| task.name.length }.max
|
48
58
|
end
|
49
59
|
|
50
|
-
|
51
|
-
def
|
52
|
-
@
|
53
|
-
.map { |task| task.args.
|
60
|
+
sig {returns(Integer)}
|
61
|
+
def max_ordered_string_length
|
62
|
+
@max_ordered_string_length ||= @tasks
|
63
|
+
.map { |task| task.args.ordered.join(' ') }
|
54
64
|
.map(&:length)
|
55
65
|
.max
|
56
66
|
end
|
57
67
|
|
58
|
-
|
59
|
-
def
|
60
|
-
@
|
68
|
+
sig {returns(T::Boolean)}
|
69
|
+
def show_ordered_args?
|
70
|
+
@show_ordered_args ||= @tasks.any? { |task| task.args.any_ordered? }
|
61
71
|
end
|
62
72
|
|
63
|
-
|
73
|
+
sig {returns(Integer)}
|
64
74
|
def max_named_string_length
|
65
75
|
@max_named_string_length ||= @tasks
|
66
76
|
.map { |task| task.args.named.join(' ') }
|
@@ -68,17 +78,12 @@ module Spud
|
|
68
78
|
.max
|
69
79
|
end
|
70
80
|
|
71
|
-
|
81
|
+
sig {returns(T::Boolean)}
|
72
82
|
def show_named_args?
|
73
83
|
@show_named_args ||= @tasks.any? { |task| task.args.any_named? }
|
74
84
|
end
|
75
85
|
|
76
|
-
|
77
|
-
def filenames
|
78
|
-
@filenames ||= @tasks.map(&:filename).uniq
|
79
|
-
end
|
80
|
-
|
81
|
-
# @return [Boolean]
|
86
|
+
sig {returns(T::Boolean)}
|
82
87
|
def show_filenames?
|
83
88
|
filenames.length > 1
|
84
89
|
end
|
data/lib/spud/task_arg.rb
CHANGED
@@ -1,39 +1,42 @@
|
|
1
|
+
# typed: strict
|
2
|
+
require 'sorbet-runtime'
|
3
|
+
|
1
4
|
module Spud
|
2
5
|
class TaskArg
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
+
extend T::Sig
|
7
|
+
|
8
|
+
sig {params(name: String, type: String, default: T.nilable(String)).void}
|
6
9
|
def initialize(name, type, default: nil)
|
7
|
-
raise 'must be of type "
|
10
|
+
raise 'must be of type "ordered" or "named"' unless %w[ordered named].include?(type)
|
8
11
|
|
9
12
|
@name = name
|
10
13
|
@type = type
|
11
14
|
@default = default
|
12
15
|
end
|
13
16
|
|
14
|
-
|
17
|
+
sig {returns(T::Boolean)}
|
15
18
|
def required?
|
16
19
|
!has_default?
|
17
20
|
end
|
18
21
|
|
19
|
-
|
22
|
+
sig {returns(T::Boolean)}
|
20
23
|
def has_default?
|
21
24
|
!!@default
|
22
25
|
end
|
23
26
|
|
24
|
-
|
25
|
-
def
|
26
|
-
@type == '
|
27
|
+
sig {returns(T::Boolean)}
|
28
|
+
def ordered?
|
29
|
+
@type == 'ordered'
|
27
30
|
end
|
28
31
|
|
29
|
-
|
32
|
+
sig {returns(T::Boolean)}
|
30
33
|
def named?
|
31
34
|
@type == 'named'
|
32
35
|
end
|
33
36
|
|
34
|
-
|
37
|
+
sig {returns(String)}
|
35
38
|
def to_s
|
36
|
-
if
|
39
|
+
if ordered?
|
37
40
|
if has_default?
|
38
41
|
"<#{@name}=#{@default}>"
|
39
42
|
else
|
data/lib/spud/task_args.rb
CHANGED
@@ -1,47 +1,49 @@
|
|
1
|
+
# typed: true
|
2
|
+
require 'sorbet-runtime'
|
1
3
|
require 'spud/task_arg'
|
2
|
-
require 'spud/
|
4
|
+
require 'spud/block_param_info'
|
3
5
|
|
4
6
|
module Spud
|
5
7
|
class TaskArgs < Array
|
6
|
-
|
7
|
-
|
8
|
-
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
sig {params(filename: String, block: Proc).returns(T.attached_class)}
|
9
11
|
def self.from_block(filename, &block)
|
10
|
-
info =
|
12
|
+
info = BlockParamInfo.new(filename, &block)
|
11
13
|
new(info.task_args)
|
12
14
|
end
|
13
15
|
|
14
|
-
|
16
|
+
sig {params(task_args: T::Array[TaskArg]).void}
|
15
17
|
def initialize(task_args)
|
16
18
|
super(task_args)
|
17
19
|
end
|
18
20
|
|
19
|
-
|
20
|
-
def
|
21
|
-
@
|
21
|
+
sig {returns(T::Array[TaskArg])}
|
22
|
+
def ordered
|
23
|
+
@ordered ||= select(&:ordered?)
|
22
24
|
end
|
23
25
|
|
24
|
-
|
25
|
-
def
|
26
|
-
@
|
26
|
+
sig {returns(T::Array[TaskArg])}
|
27
|
+
def required_ordered
|
28
|
+
@required_ordered ||= ordered.select(&:required?)
|
27
29
|
end
|
28
30
|
|
29
|
-
|
30
|
-
def
|
31
|
-
!
|
31
|
+
sig {returns(T::Boolean)}
|
32
|
+
def any_ordered?
|
33
|
+
!ordered.empty?
|
32
34
|
end
|
33
35
|
|
34
|
-
|
36
|
+
sig {returns(T::Array[TaskArg])}
|
35
37
|
def named
|
36
38
|
@named ||= select(&:named?)
|
37
39
|
end
|
38
40
|
|
39
|
-
|
41
|
+
sig {returns(T::Array[TaskArg])}
|
40
42
|
def required_named
|
41
43
|
@required_named ||= named.select(&:required?)
|
42
44
|
end
|
43
45
|
|
44
|
-
|
46
|
+
sig {returns(T::Boolean)}
|
45
47
|
def any_named?
|
46
48
|
!named.empty?
|
47
49
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# typed: strict
|
2
|
+
require 'sorbet-runtime'
|
3
|
+
require 'stringio'
|
4
|
+
require 'spud/driver'
|
5
|
+
require 'spud/task_runners/task'
|
6
|
+
|
7
|
+
module Spud
|
8
|
+
module TaskRunners
|
9
|
+
module Make
|
10
|
+
class Task < TaskRunners::Task
|
11
|
+
extend T::Sig
|
12
|
+
|
13
|
+
sig {override.returns(String)}
|
14
|
+
attr_reader :name
|
15
|
+
|
16
|
+
sig {override.params(driver: Driver).returns(T::Array[TaskRunners::Task])}
|
17
|
+
def self.tasks(driver)
|
18
|
+
return [] unless File.exist?('Makefile')
|
19
|
+
|
20
|
+
if `command -v make`.empty?
|
21
|
+
puts 'Makefile detected, but no installation of `make` exists. Skipping make...'
|
22
|
+
return []
|
23
|
+
end
|
24
|
+
|
25
|
+
source = File.read('Makefile')
|
26
|
+
T.unsafe(source.scan(/^(\S+):.*/)).map(&:first).map do |name|
|
27
|
+
new(driver, name)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
sig {params(driver: Driver, name: String).void}
|
32
|
+
def initialize(driver, name)
|
33
|
+
@driver = driver
|
34
|
+
@name = name
|
35
|
+
end
|
36
|
+
|
37
|
+
sig {override.params(ordered: T::Array[String], named: T::Hash[String, String]).returns(T.untyped)}
|
38
|
+
def invoke(ordered, named)
|
39
|
+
system('make', name)
|
40
|
+
end
|
41
|
+
|
42
|
+
sig {override.returns(String)}
|
43
|
+
def filename
|
44
|
+
'Makefile'
|
45
|
+
end
|
46
|
+
|
47
|
+
sig {override.returns(String)}
|
48
|
+
def details
|
49
|
+
source = File.read('Makefile')
|
50
|
+
lines = source.split("\n")
|
51
|
+
cursor = 0
|
52
|
+
|
53
|
+
cursor += 1 until lines[cursor]&.start_with?(name)
|
54
|
+
|
55
|
+
builder = StringIO.new
|
56
|
+
until lines[cursor]&.empty?
|
57
|
+
builder.puts lines[cursor]
|
58
|
+
cursor += 1
|
59
|
+
end
|
60
|
+
|
61
|
+
builder.string
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# typed: strict
|
2
|
+
require 'sorbet-runtime'
|
3
|
+
require 'json'
|
4
|
+
require 'spud/driver'
|
5
|
+
require 'spud/task_args'
|
6
|
+
require 'spud/task_runners/task'
|
7
|
+
|
8
|
+
module Spud
|
9
|
+
module TaskRunners
|
10
|
+
module PackageJSON
|
11
|
+
class Task < TaskRunners::Task
|
12
|
+
extend T::Sig
|
13
|
+
|
14
|
+
sig {override.returns(String)}
|
15
|
+
attr_reader :name
|
16
|
+
|
17
|
+
sig {override.params(driver: Driver).returns(T::Array[TaskRunners::Task])}
|
18
|
+
def self.tasks(driver)
|
19
|
+
if File.exist?('package.lock')
|
20
|
+
if `command -v npm`.empty?
|
21
|
+
puts 'package.json detected, but no installation of `npm` exists. Skipping npm...'
|
22
|
+
return []
|
23
|
+
else
|
24
|
+
command = 'npm'
|
25
|
+
end
|
26
|
+
elsif File.exist?('yarn.lock')
|
27
|
+
if `command -v yarn`.empty?
|
28
|
+
puts 'package.json detected, but no installation of `yarn` exists. Skipping yarn...'
|
29
|
+
return []
|
30
|
+
else
|
31
|
+
command = 'yarn'
|
32
|
+
end
|
33
|
+
else
|
34
|
+
return []
|
35
|
+
end
|
36
|
+
|
37
|
+
source = File.read('package.json')
|
38
|
+
json = JSON.parse(source)
|
39
|
+
scripts = json['scripts']
|
40
|
+
return [] unless scripts
|
41
|
+
|
42
|
+
scripts.keys.map { |name| new(driver, name, command, scripts) }
|
43
|
+
end
|
44
|
+
|
45
|
+
sig {params(driver: Driver, name: String, command: String, scripts: T::Hash[String, String]).void}
|
46
|
+
def initialize(driver, name, command, scripts)
|
47
|
+
@driver = driver
|
48
|
+
@name = name
|
49
|
+
@command = command
|
50
|
+
@scripts = scripts
|
51
|
+
end
|
52
|
+
|
53
|
+
sig {override.params(ordered: T::Array[String], named: T::Hash[String, String]).returns(T.untyped)}
|
54
|
+
def invoke(ordered, named)
|
55
|
+
system("#{@command} run #{name}")
|
56
|
+
end
|
57
|
+
|
58
|
+
sig {override.returns(String)}
|
59
|
+
def filename
|
60
|
+
'package.json'
|
61
|
+
end
|
62
|
+
|
63
|
+
sig {override.returns(String)}
|
64
|
+
def details
|
65
|
+
%({ "#{name}": "#{@scripts[name]}" })
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# typed: true
|
2
|
+
require 'sorbet-runtime'
|
3
|
+
require 'spud/driver'
|
4
|
+
require 'spud/task_runners/spud_task_runner/task'
|
5
|
+
|
6
|
+
module Spud
|
7
|
+
module TaskRunners
|
8
|
+
module SpudTaskRunner
|
9
|
+
class FileDSL
|
10
|
+
extend T::Sig
|
11
|
+
|
12
|
+
sig {params(driver: Driver, filename: String).returns(T::Array[SpudTaskRunner::Task])}
|
13
|
+
def self.run(driver, filename)
|
14
|
+
dsl = new(driver, filename)
|
15
|
+
dsl.instance_eval(::File.read(filename), filename)
|
16
|
+
|
17
|
+
dsl.instance_variable_get(:@__tasks)
|
18
|
+
end
|
19
|
+
|
20
|
+
sig {params(driver: Driver, filename: String).void}
|
21
|
+
def initialize(driver, filename)
|
22
|
+
@__driver = driver
|
23
|
+
@__filename = filename
|
24
|
+
|
25
|
+
@__tasks = T.let([], T::Array[Task])
|
26
|
+
end
|
27
|
+
|
28
|
+
sig {params(name: String).returns(T::Boolean)}
|
29
|
+
def require_relative(name)
|
30
|
+
require("./#{name}")
|
31
|
+
end
|
32
|
+
|
33
|
+
sig do
|
34
|
+
params(
|
35
|
+
name: T.any(String, Symbol),
|
36
|
+
dependencies: T::Hash[T.any(String, T::Array[String]), T.any(String, T::Array[String])],
|
37
|
+
block: Proc,
|
38
|
+
).void
|
39
|
+
end
|
40
|
+
def task(name, dependencies = {}, &block)
|
41
|
+
@__tasks << Task.new(
|
42
|
+
driver: @__driver,
|
43
|
+
name: Task.qualified_name(@__filename, name.to_s),
|
44
|
+
filename: @__filename,
|
45
|
+
dependencies: dependencies,
|
46
|
+
&block
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
def method_missing(name, *args, &block)
|
51
|
+
T.unsafe(self).task(name, *args, &block)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# typed: true
|
2
|
+
require 'sorbet-runtime'
|
3
|
+
require 'stringio'
|
4
|
+
require 'open3'
|
5
|
+
require 'spud/driver'
|
6
|
+
require 'spud/task_runners/spud_task_runner/shell/result'
|
7
|
+
|
8
|
+
module Spud
|
9
|
+
module TaskRunners
|
10
|
+
module SpudTaskRunner
|
11
|
+
module Shell
|
12
|
+
class Command
|
13
|
+
extend T::Sig
|
14
|
+
|
15
|
+
attr_reader :result
|
16
|
+
|
17
|
+
sig {params(driver: Driver, command: String, silent: T::Boolean, handle: T.any(IO, StringIO)).returns(Result)}
|
18
|
+
def self.call(driver, command, silent: false, handle: STDOUT)
|
19
|
+
cmd = new(driver, command, silent: silent, handle: handle)
|
20
|
+
cmd.issue!
|
21
|
+
cmd.result
|
22
|
+
end
|
23
|
+
|
24
|
+
sig {params(driver: Driver, command: String, silent: T::Boolean, handle: T.any(IO, StringIO)).void}
|
25
|
+
def initialize(driver, command, silent: false, handle: STDOUT)
|
26
|
+
@command = command
|
27
|
+
@driver = driver
|
28
|
+
@silent = silent
|
29
|
+
@handle = handle
|
30
|
+
|
31
|
+
@result = T.let(nil, T.nilable(Result))
|
32
|
+
end
|
33
|
+
|
34
|
+
sig {void}
|
35
|
+
def issue!
|
36
|
+
capturer = StringIO.new
|
37
|
+
|
38
|
+
Open3.popen2e(@command) do |_stdin, stdout, thread|
|
39
|
+
@driver.register_subprocess(thread.pid)
|
40
|
+
|
41
|
+
loop do
|
42
|
+
line = stdout.gets
|
43
|
+
break unless line
|
44
|
+
|
45
|
+
@handle.write line unless @silent
|
46
|
+
capturer.puts line
|
47
|
+
end
|
48
|
+
|
49
|
+
@result = Result.new(capturer.string, T.cast(thread.value, Process::Status))
|
50
|
+
end
|
51
|
+
|
52
|
+
@driver.register_subprocess(nil)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|