spud 0.2.0 → 0.2.5
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 +23 -19
- data/lib/spud/cli/results.rb +18 -11
- data/lib/spud/driver.rb +135 -0
- data/lib/spud/error.rb +1 -0
- data/lib/spud/help.rb +13 -13
- data/lib/spud/lister.rb +27 -22
- data/lib/spud/shell/command.rb +75 -0
- data/lib/spud/shell/result.rb +33 -0
- data/lib/spud/task_arg.rb +24 -12
- data/lib/spud/task_args.rb +20 -18
- data/lib/spud/task_runners/make/task.rb +67 -0
- data/lib/spud/task_runners/package.json/task.rb +71 -0
- data/lib/spud/task_runners/spud_task_runner/dependency.rb +49 -0
- data/lib/spud/task_runners/spud_task_runner/file_dsl.rb +57 -0
- data/lib/spud/task_runners/spud_task_runner/task.rb +148 -0
- data/lib/spud/task_runners/spud_task_runner/task_dsl.rb +90 -0
- data/lib/spud/task_runners/task.rb +40 -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 -16
- 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/shell/result.rb +0 -26
- data/lib/spud/build_tools/spud/task.rb +0 -125
- data/lib/spud/build_tools/task.rb +0 -33
- data/lib/spud/options.rb +0 -14
- data/lib/spud/runtime.rb +0 -104
data/lib/spud/help.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# typed: true
|
1
2
|
require 'stringio'
|
2
3
|
require 'spud/version'
|
3
4
|
|
@@ -5,19 +6,18 @@ module Spud
|
|
5
6
|
module Help
|
6
7
|
# @return [void]
|
7
8
|
def self.print!
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
puts help.string
|
9
|
+
puts <<~HELP
|
10
|
+
spud #{VERSION}
|
11
|
+
|
12
|
+
usage:
|
13
|
+
spud [options] <task> [args]
|
14
|
+
|
15
|
+
options:
|
16
|
+
-h, --help show this help dialog
|
17
|
+
-w, --watch <glob> re-run task any time glob changes
|
18
|
+
-f, --files list parsed files
|
19
|
+
-i, --inspect show details about a task
|
20
|
+
HELP
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
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
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# typed: true
|
2
|
+
require 'sorbet-runtime'
|
3
|
+
require 'stringio'
|
4
|
+
require 'open3'
|
5
|
+
require 'spud/driver'
|
6
|
+
require 'spud/shell/result'
|
7
|
+
|
8
|
+
module Spud
|
9
|
+
module Shell
|
10
|
+
class Command
|
11
|
+
extend T::Sig
|
12
|
+
|
13
|
+
attr_reader :result
|
14
|
+
|
15
|
+
Handle = T.type_alias {T.any(IO, StringIO)}
|
16
|
+
|
17
|
+
sig {params(command: String, driver: T.nilable(Driver), silent: T::Boolean, handle: Handle).returns(Result)}
|
18
|
+
def self.call(command, driver: nil, silent: false, handle: STDOUT)
|
19
|
+
cmd = new(command, driver: driver, silent: silent, handle: handle)
|
20
|
+
cmd.issue!
|
21
|
+
cmd.result
|
22
|
+
end
|
23
|
+
|
24
|
+
sig {params(driver: Driver).returns(Commander)}
|
25
|
+
def self.commander(driver)
|
26
|
+
Commander.new(driver)
|
27
|
+
end
|
28
|
+
|
29
|
+
sig {params(command: String, driver: T.nilable(Driver), silent: T::Boolean, handle: Handle).void}
|
30
|
+
def initialize(command, driver: nil, silent: false, handle: STDOUT)
|
31
|
+
@command = command
|
32
|
+
@driver = driver
|
33
|
+
@silent = silent
|
34
|
+
@handle = handle
|
35
|
+
|
36
|
+
@result = T.let(nil, T.nilable(Result))
|
37
|
+
end
|
38
|
+
|
39
|
+
sig {void}
|
40
|
+
def issue!
|
41
|
+
capturer = StringIO.new
|
42
|
+
|
43
|
+
Open3.popen2e(@command) do |_, out, thread|
|
44
|
+
@driver&.register_subprocess(thread.pid)
|
45
|
+
|
46
|
+
loop do
|
47
|
+
line = out.gets
|
48
|
+
break unless line
|
49
|
+
|
50
|
+
@handle.write line unless @silent
|
51
|
+
capturer.puts line
|
52
|
+
end
|
53
|
+
|
54
|
+
@result = Result.new(capturer.string, T.cast(thread.value, Process::Status))
|
55
|
+
end
|
56
|
+
|
57
|
+
@driver&.register_subprocess(nil)
|
58
|
+
end
|
59
|
+
|
60
|
+
class Commander
|
61
|
+
extend T::Sig
|
62
|
+
|
63
|
+
sig {params(driver: Driver).void}
|
64
|
+
def initialize(driver)
|
65
|
+
@driver = driver
|
66
|
+
end
|
67
|
+
|
68
|
+
sig {params(command: String, silent: T::Boolean, handle: Handle).returns(Result)}
|
69
|
+
def call(command, silent: false, handle: STDOUT)
|
70
|
+
Command.(command, driver: @driver, silent: silent, handle: handle)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# typed: strict
|
2
|
+
require 'sorbet-runtime'
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
module Spud
|
6
|
+
module Shell
|
7
|
+
class Result < String
|
8
|
+
extend T::Sig
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
sig {returns(Process::Status)}
|
12
|
+
attr_reader :status
|
13
|
+
|
14
|
+
def_delegators :status,
|
15
|
+
:coredump?,
|
16
|
+
:exited?,
|
17
|
+
:exitstatus,
|
18
|
+
:pid,
|
19
|
+
:signaled?,
|
20
|
+
:stopped?,
|
21
|
+
:stopsig,
|
22
|
+
:success?,
|
23
|
+
:termsig,
|
24
|
+
:to_i
|
25
|
+
|
26
|
+
sig {params(output: String, status: Process::Status).void}
|
27
|
+
def initialize(output, status)
|
28
|
+
super(output)
|
29
|
+
@status = status
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/spud/task_arg.rb
CHANGED
@@ -1,39 +1,51 @@
|
|
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 {returns(String)}
|
9
|
+
attr_reader :name
|
10
|
+
|
11
|
+
sig {returns(String)}
|
12
|
+
attr_reader :type
|
13
|
+
|
14
|
+
sig {returns(T.nilable(String))}
|
15
|
+
attr_reader :default
|
16
|
+
|
17
|
+
sig {params(name: String, type: String, default: T.nilable(String)).void}
|
6
18
|
def initialize(name, type, default: nil)
|
7
|
-
raise 'must be of type "
|
19
|
+
raise 'must be of type "ordered" or "named"' unless %w[ordered named].include?(type)
|
8
20
|
|
9
21
|
@name = name
|
10
22
|
@type = type
|
11
23
|
@default = default
|
12
24
|
end
|
13
25
|
|
14
|
-
|
26
|
+
sig {returns(T::Boolean)}
|
15
27
|
def required?
|
16
28
|
!has_default?
|
17
29
|
end
|
18
30
|
|
19
|
-
|
31
|
+
sig {returns(T::Boolean)}
|
20
32
|
def has_default?
|
21
33
|
!!@default
|
22
34
|
end
|
23
35
|
|
24
|
-
|
25
|
-
def
|
26
|
-
@type == '
|
36
|
+
sig {returns(T::Boolean)}
|
37
|
+
def ordered?
|
38
|
+
@type == 'ordered'
|
27
39
|
end
|
28
40
|
|
29
|
-
|
41
|
+
sig {returns(T::Boolean)}
|
30
42
|
def named?
|
31
43
|
@type == 'named'
|
32
44
|
end
|
33
45
|
|
34
|
-
|
46
|
+
sig {returns(String)}
|
35
47
|
def to_s
|
36
|
-
if
|
48
|
+
if ordered?
|
37
49
|
if has_default?
|
38
50
|
"<#{@name}=#{@default}>"
|
39
51
|
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,67 @@
|
|
1
|
+
# typed: strict
|
2
|
+
require 'sorbet-runtime'
|
3
|
+
require 'stringio'
|
4
|
+
require 'spud/driver'
|
5
|
+
require 'spud/shell/command'
|
6
|
+
require 'spud/task_runners/task'
|
7
|
+
|
8
|
+
module Spud
|
9
|
+
module TaskRunners
|
10
|
+
module Make
|
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
|
+
return [] unless File.exist?('Makefile')
|
20
|
+
|
21
|
+
if `command -v make`.empty?
|
22
|
+
puts 'Makefile detected, but no installation of `make` exists. Skipping make...'
|
23
|
+
return []
|
24
|
+
end
|
25
|
+
|
26
|
+
source = File.read('Makefile')
|
27
|
+
T.unsafe(source.scan(/^(\S+):.*/)).map(&:first).map do |name|
|
28
|
+
new(driver, name)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
sig {params(driver: Driver, name: String).void}
|
33
|
+
def initialize(driver, name)
|
34
|
+
@driver = driver
|
35
|
+
@name = name
|
36
|
+
end
|
37
|
+
|
38
|
+
sig {override.params(ordered: T::Array[String], named: T::Hash[String, String]).returns(T.untyped)}
|
39
|
+
def invoke(ordered, named)
|
40
|
+
Shell::Command.("make #{name}", driver: @driver)
|
41
|
+
end
|
42
|
+
|
43
|
+
sig {override.returns(String)}
|
44
|
+
def filename
|
45
|
+
'Makefile'
|
46
|
+
end
|
47
|
+
|
48
|
+
sig {override.returns(String)}
|
49
|
+
def details
|
50
|
+
source = File.read('Makefile')
|
51
|
+
lines = source.split("\n")
|
52
|
+
cursor = 0
|
53
|
+
|
54
|
+
cursor += 1 until lines[cursor]&.start_with?(name)
|
55
|
+
|
56
|
+
builder = StringIO.new
|
57
|
+
while lines[cursor] && !lines[cursor]&.empty?
|
58
|
+
builder.puts lines[cursor]
|
59
|
+
cursor += 1
|
60
|
+
end
|
61
|
+
|
62
|
+
builder.string
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# typed: strict
|
2
|
+
require 'sorbet-runtime'
|
3
|
+
require 'json'
|
4
|
+
require 'spud/driver'
|
5
|
+
require 'spud/task_args'
|
6
|
+
require 'spud/shell/command'
|
7
|
+
require 'spud/task_runners/task'
|
8
|
+
|
9
|
+
module Spud
|
10
|
+
module TaskRunners
|
11
|
+
module PackageJSON
|
12
|
+
class Task < TaskRunners::Task
|
13
|
+
extend T::Sig
|
14
|
+
|
15
|
+
sig {override.returns(String)}
|
16
|
+
attr_reader :name
|
17
|
+
|
18
|
+
sig {override.params(driver: Driver).returns(T::Array[TaskRunners::Task])}
|
19
|
+
def self.tasks(driver)
|
20
|
+
if File.exist?('package.lock')
|
21
|
+
if `command -v npm`.empty?
|
22
|
+
puts 'package.json detected, but no installation of `npm` exists. Skipping npm...'
|
23
|
+
return []
|
24
|
+
else
|
25
|
+
command = 'npm'
|
26
|
+
end
|
27
|
+
elsif File.exist?('yarn.lock')
|
28
|
+
if `command -v yarn`.empty?
|
29
|
+
puts 'package.json detected, but no installation of `yarn` exists. Skipping yarn...'
|
30
|
+
return []
|
31
|
+
else
|
32
|
+
command = 'yarn'
|
33
|
+
end
|
34
|
+
else
|
35
|
+
return []
|
36
|
+
end
|
37
|
+
|
38
|
+
source = File.read('package.json')
|
39
|
+
json = JSON.parse(source)
|
40
|
+
scripts = json['scripts']
|
41
|
+
return [] unless scripts
|
42
|
+
|
43
|
+
scripts.keys.map { |name| new(driver, name, command, scripts) }
|
44
|
+
end
|
45
|
+
|
46
|
+
sig {params(driver: Driver, name: String, command: String, scripts: T::Hash[String, String]).void}
|
47
|
+
def initialize(driver, name, command, scripts)
|
48
|
+
@driver = driver
|
49
|
+
@name = name
|
50
|
+
@command = command
|
51
|
+
@scripts = scripts
|
52
|
+
end
|
53
|
+
|
54
|
+
sig {override.params(ordered: T::Array[String], named: T::Hash[String, String]).returns(T.untyped)}
|
55
|
+
def invoke(ordered, named)
|
56
|
+
Shell::Command.("#{@command} run #{name}", driver: @driver)
|
57
|
+
end
|
58
|
+
|
59
|
+
sig {override.returns(String)}
|
60
|
+
def filename
|
61
|
+
'package.json'
|
62
|
+
end
|
63
|
+
|
64
|
+
sig {override.returns(String)}
|
65
|
+
def details
|
66
|
+
%({ "#{name}": "#{@scripts[name]}" })
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|