spud 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  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 +22 -19
  6. data/lib/spud/cli/results.rb +18 -11
  7. data/lib/spud/driver.rb +134 -0
  8. data/lib/spud/error.rb +1 -0
  9. data/lib/spud/help.rb +13 -14
  10. data/lib/spud/lister.rb +27 -22
  11. data/lib/spud/task_arg.rb +15 -12
  12. data/lib/spud/task_args.rb +20 -18
  13. data/lib/spud/task_runners/make/task.rb +66 -0
  14. data/lib/spud/task_runners/package.json/task.rb +70 -0
  15. data/lib/spud/{build_tools/spud → task_runners/spud_task_runner}/dependency.rb +3 -2
  16. data/lib/spud/task_runners/spud_task_runner/file_dsl.rb +56 -0
  17. data/lib/spud/task_runners/spud_task_runner/shell/command.rb +58 -0
  18. data/lib/spud/{build_tools/spud → task_runners/spud_task_runner}/shell/result.rb +9 -4
  19. data/lib/spud/task_runners/spud_task_runner/task.rb +143 -0
  20. data/lib/spud/task_runners/spud_task_runner/task_dsl.rb +82 -0
  21. data/lib/spud/task_runners/task.rb +43 -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 +46 -17
  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/task.rb +0 -177
  34. data/lib/spud/build_tools/task.rb +0 -41
  35. data/lib/spud/options.rb +0 -14
  36. data/lib/spud/runtime.rb +0 -114
@@ -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
@@ -1,39 +1,42 @@
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 {params(name: String, type: String, default: T.nilable(String)).void}
6
9
  def initialize(name, type, default: nil)
7
- raise 'must be of type "positional" or "named"' unless %w[positional named].include?(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
- # @return [Boolean]
17
+ sig {returns(T::Boolean)}
15
18
  def required?
16
19
  !has_default?
17
20
  end
18
21
 
19
- # @return [Boolean]
22
+ sig {returns(T::Boolean)}
20
23
  def has_default?
21
24
  !!@default
22
25
  end
23
26
 
24
- # @return [Boolean]
25
- def positional?
26
- @type == 'positional'
27
+ sig {returns(T::Boolean)}
28
+ def ordered?
29
+ @type == 'ordered'
27
30
  end
28
31
 
29
- # @return [Boolean]
32
+ sig {returns(T::Boolean)}
30
33
  def named?
31
34
  @type == 'named'
32
35
  end
33
36
 
34
- # @return [String]
37
+ sig {returns(String)}
35
38
  def to_s
36
- if positional?
39
+ if ordered?
37
40
  if has_default?
38
41
  "<#{@name}=#{@default}>"
39
42
  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,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
@@ -1,6 +1,7 @@
1
+ # typed: true
1
2
  module Spud
2
- module BuildTools
3
- module Spud
3
+ module TaskRunners
4
+ module SpudTaskRunner
4
5
  class Dependency
5
6
  def initialize(source, target)
6
7
  @sources = [source].flatten
@@ -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