spud 0.2.1 → 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +5 -5
  2. data/lib/spud.rb +3 -2
  3. data/lib/spud/block_param_info.rb +80 -0
  4. data/lib/spud/cli/options.rb +35 -0
  5. data/lib/spud/cli/parser.rb +23 -19
  6. data/lib/spud/cli/results.rb +18 -11
  7. data/lib/spud/driver.rb +136 -0
  8. data/lib/spud/error.rb +6 -1
  9. data/lib/spud/help.rb +17 -14
  10. data/lib/spud/lister.rb +27 -22
  11. data/lib/spud/shell/command.rb +75 -0
  12. data/lib/spud/shell/result.rb +33 -0
  13. data/lib/spud/task_arg.rb +24 -12
  14. data/lib/spud/task_args.rb +20 -18
  15. data/lib/spud/task_runners/make/task.rb +67 -0
  16. data/lib/spud/task_runners/package.json/task.rb +71 -0
  17. data/lib/spud/task_runners/spud_task_runner/dependency.rb +50 -0
  18. data/lib/spud/task_runners/spud_task_runner/file_dsl.rb +57 -0
  19. data/lib/spud/task_runners/spud_task_runner/task.rb +149 -0
  20. data/lib/spud/task_runners/spud_task_runner/task_dsl.rb +95 -0
  21. data/lib/spud/task_runners/task.rb +40 -0
  22. data/lib/spud/task_runners/task_runners.rb +25 -0
  23. data/lib/spud/version.rb +2 -1
  24. data/lib/spud/watch.rb +73 -0
  25. metadata +51 -20
  26. data/lib/spud/build_tools/build_tools.rb +0 -13
  27. data/lib/spud/build_tools/make/task.rb +0 -27
  28. data/lib/spud/build_tools/package.json/task.rb +0 -47
  29. data/lib/spud/build_tools/spud/block_param_info.rb +0 -77
  30. data/lib/spud/build_tools/spud/dsl/file.rb +0 -23
  31. data/lib/spud/build_tools/spud/dsl/task.rb +0 -63
  32. data/lib/spud/build_tools/spud/shell/command.rb +0 -52
  33. data/lib/spud/build_tools/spud/shell/result.rb +0 -26
  34. data/lib/spud/build_tools/spud/task.rb +0 -125
  35. data/lib/spud/build_tools/task.rb +0 -33
  36. data/lib/spud/options.rb +0 -14
  37. data/lib/spud/runtime.rb +0 -104
@@ -1,23 +1,26 @@
1
+ # typed: true
2
+ require 'sorbet-runtime'
1
3
  require 'stringio'
2
4
  require 'spud/version'
3
5
 
4
6
  module Spud
5
7
  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'
8
+ extend T::Sig
19
9
 
20
- puts help.string
10
+ sig {void}
11
+ def self.print!
12
+ puts <<~HELP
13
+ spud #{VERSION}
14
+
15
+ usage:
16
+ spud [options] <task> [args]
17
+
18
+ options:
19
+ -h, --help show this help dialog
20
+ -w, --watch <glob> re-run task any time glob changes
21
+ -f, --files list parsed files
22
+ -i, --inspect show details about a task
23
+ HELP
21
24
  end
22
25
  end
23
26
  end
@@ -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
- # @param tasks [Array<BuildTools::Task>]
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
- # @return [void]
11
- def list!
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 show_positional_args?
22
+ if show_ordered_args?
18
23
  builder.write ' '
19
- builder.write task.args.positional.join(' ').ljust(max_positional_string_length)
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
- # @return [void]
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
- # @return [Integer]
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
- # @return [Integer]
51
- def max_positional_string_length
52
- @max_positional_string_length ||= @tasks
53
- .map { |task| task.args.positional.join(' ') }
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
- # @return [Boolean]
59
- def show_positional_args?
60
- @show_positional_args ||= @tasks.any? { |task| task.args.any_positional? }
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
- # @return [Integer]
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
- # @return [Boolean]
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
- # @return [Array<String>]
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
@@ -1,39 +1,51 @@
1
+ # typed: strict
2
+ require 'sorbet-runtime'
3
+
1
4
  module Spud
2
5
  class TaskArg
3
- # @param name [String]
4
- # @param type [String]
5
- # @param default [String]
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 "positional" or "named"' unless %w[positional named].include?(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
- # @return [Boolean]
26
+ sig {returns(T::Boolean)}
15
27
  def required?
16
28
  !has_default?
17
29
  end
18
30
 
19
- # @return [Boolean]
31
+ sig {returns(T::Boolean)}
20
32
  def has_default?
21
33
  !!@default
22
34
  end
23
35
 
24
- # @return [Boolean]
25
- def positional?
26
- @type == 'positional'
36
+ sig {returns(T::Boolean)}
37
+ def ordered?
38
+ @type == 'ordered'
27
39
  end
28
40
 
29
- # @return [Boolean]
41
+ sig {returns(T::Boolean)}
30
42
  def named?
31
43
  @type == 'named'
32
44
  end
33
45
 
34
- # @return [String]
46
+ sig {returns(String)}
35
47
  def to_s
36
- if positional?
48
+ if ordered?
37
49
  if has_default?
38
50
  "<#{@name}=#{@default}>"
39
51
  else
@@ -1,47 +1,49 @@
1
+ # typed: true
2
+ require 'sorbet-runtime'
1
3
  require 'spud/task_arg'
2
- require 'spud/build_tools/spud/block_param_info'
4
+ require 'spud/block_param_info'
3
5
 
4
6
  module Spud
5
7
  class TaskArgs < Array
6
- # @param filename [String]
7
- # @param block [Proc]
8
- # @return [Spud::TaskArgs]
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 = BuildTools::Spud::BlockParamInfo.new(filename, &block)
12
+ info = BlockParamInfo.new(filename, &block)
11
13
  new(info.task_args)
12
14
  end
13
15
 
14
- # @param task_args [Array<Spud::TaskArg>]
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
- # @return [Array<Spud::TaskArg>]
20
- def positional
21
- @positional ||= select(&:positional?)
21
+ sig {returns(T::Array[TaskArg])}
22
+ def ordered
23
+ @ordered ||= select(&:ordered?)
22
24
  end
23
25
 
24
- # @return [Array<Spud::TaskArg>]
25
- def required_positional
26
- @required_positional ||= positional.select(&:required?)
26
+ sig {returns(T::Array[TaskArg])}
27
+ def required_ordered
28
+ @required_ordered ||= ordered.select(&:required?)
27
29
  end
28
30
 
29
- # @return [Boolean]
30
- def any_positional?
31
- !positional.empty?
31
+ sig {returns(T::Boolean)}
32
+ def any_ordered?
33
+ !ordered.empty?
32
34
  end
33
35
 
34
- # @return [Array<Spud::TaskArg>]
36
+ sig {returns(T::Array[TaskArg])}
35
37
  def named
36
38
  @named ||= select(&:named?)
37
39
  end
38
40
 
39
- # @return [Array<Spud::TaskArg>]
41
+ sig {returns(T::Array[TaskArg])}
40
42
  def required_named
41
43
  @required_named ||= named.select(&:required?)
42
44
  end
43
45
 
44
- # @return [Boolean]
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