spud 0.2.0 → 0.2.5
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 +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
|