brut 0.18.2 → 0.19.0

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.
@@ -1,4 +1,5 @@
1
1
  require "optparse"
2
+ require "pathname"
2
3
  require "brut/framework/project_environment"
3
4
 
4
5
  # Parses the command line and makes everything parsed available as attributes.
@@ -30,7 +31,7 @@ class Brut::CLI::ParsedCommandLine
30
31
  # for `#command` may be a command that outputs an error.
31
32
  def initialize(app_command:, argv:, env:)
32
33
  brut_provided_help_requested = false
33
- app_option_parser = new_option_parser do |opts|
34
+ app_option_parser = new_option_parser(app_command.name) do |opts|
34
35
  opts.banner = app_command.description
35
36
  app_command.accepts.each_with_index { |class_or_class_and_proc,index| accept(opts,class_or_class_and_proc,index) }
36
37
  app_command.opts.each do |option|
@@ -41,9 +42,7 @@ class Brut::CLI::ParsedCommandLine
41
42
  end
42
43
  end
43
44
 
44
- options = {
45
- 'log-level': "error",
46
- }
45
+ options = {}
47
46
  remaining_argv = app_option_parser.order!(argv,into: options)
48
47
 
49
48
  if remaining_argv[0] == "help"
@@ -72,7 +71,7 @@ class Brut::CLI::ParsedCommandLine
72
71
 
73
72
 
74
73
  if command != app_command
75
- command_option_parser = new_option_parser do |opts|
74
+ command_option_parser = new_option_parser(app_command.name) do |opts|
76
75
  opts.banner = command.description
77
76
  app_command.accepts.each_with_index { |class_or_class_and_proc,index| accept(opts,class_or_class_and_proc,index) }
78
77
  command.accepts.each_with_index { |class_or_class_and_proc,index| accept(opts,class_or_class_and_proc,index) }
@@ -92,10 +91,6 @@ class Brut::CLI::ParsedCommandLine
92
91
 
93
92
  if help_command
94
93
  command = help_command
95
- else
96
- if remaining_argv.empty? && command.default_command
97
- command = command.default_command
98
- end
99
94
  end
100
95
 
101
96
  if options[:env]
@@ -105,6 +100,28 @@ class Brut::CLI::ParsedCommandLine
105
100
  @command = command
106
101
  @argv = remaining_argv
107
102
  @options = Brut::CLI::Options.new(options)
103
+ if !@options.log_level?
104
+ if @options.verbose? || @options.debug?
105
+ @options[:'log-level'] = "debug"
106
+ elsif @options.quiet?
107
+ @options[:'log-level'] = "error"
108
+ else
109
+ @options[:'log-level'] = "info"
110
+ end
111
+ end
112
+ if !@options[:'log-file']
113
+ log_file_path = if env["XDG_STATE_HOME"]
114
+ Pathname(env["XDG_STATE_HOME"]) / "brut"
115
+ elsif env["HOME"]
116
+ Pathname("#{env['HOME']}/.local/state/") / "brut"
117
+ else
118
+ Pathname("/tmp/") / "brut"
119
+ end
120
+ @options[:'log-file'] = log_file_path / (app_command.name + ".log")
121
+ end
122
+ if @options[:'log-stdout'].nil?
123
+ @options[:'log-stdout'] = @options.verbose? || @options.debug?
124
+ end
108
125
  rescue => ex
109
126
  @command = if env["BRUT_DEBUG"] == "true"
110
127
  Brut::CLI::Commands::RaiseError.new(ex)
@@ -117,7 +134,7 @@ class Brut::CLI::ParsedCommandLine
117
134
 
118
135
  private
119
136
 
120
- def new_option_parser(&block)
137
+ def new_option_parser(app_name, &block)
121
138
  OptionParser.new do |opts|
122
139
  opts.accept(Brut::Framework::ProjectEnvironment) do |value|
123
140
  Brut::Framework::ProjectEnvironment.new(value)
@@ -126,6 +143,12 @@ private
126
143
  "Project environment, e.g. test, development, production. Default depends on the command")
127
144
  opts.on("--log-level=LOG_LEVEL", [ "debug", "info", "warn", "error", "fatal" ],
128
145
  "Log level, which should be debug, info, warn, error, or fatal. Defaults to error")
146
+ opts.on("--verbose", "Set log level to debug, and show log messages on stdout")
147
+ opts.on("--debug", "Set log level to debug, and show log messages on stdout")
148
+ opts.on("--quiet", "Set log level to error")
149
+ opts.on("--log-file=FILE",
150
+ "Path to a file where log messages are written. Defaults to $XDG_CACHE_HOME/brut/logs/#{app_name}.log")
151
+ opts.on("--[no-]log-stdout", "Log messages to stdout in addition to the log file")
129
152
  block.(opts)
130
153
  end
131
154
  end
@@ -11,18 +11,19 @@ class Brut::CLI::Runner
11
11
  # @param [IO] stdin the standard input
12
12
  # @param [Pathname] project_root root of the Brut project (i.e. where `Gemfile`, `app` et. al. are located)
13
13
  def initialize(app_command, stdout:, stderr:,stdin:, project_root:)
14
- prefix = if $0 =~ /\/brut$/
15
- "brut"
16
- else
17
- $0
18
- end
14
+ @app_name = if $0 =~ /\/brut$/
15
+ "brut #{app_command.name}"
16
+ else
17
+ $0
18
+ end
19
19
  @app_command = app_command
20
- @stdout = Brut::CLI::Output.new(io: stdout, prefix: "[ #{prefix} ] ")
21
- @stderr = Brut::CLI::Output.new(io: stderr, prefix: "[ #{prefix} ] ")
20
+ @stdout = stdout
21
+ @stderr = stderr
22
22
  @stdin = stdin
23
23
  @project_root = project_root
24
24
  end
25
25
 
26
+
26
27
  # Run the commmand or subcommand based on the `app_command` given to the constructor and the command line
27
28
  # provided in `argv`.
28
29
  #
@@ -35,6 +36,13 @@ class Brut::CLI::Runner
35
36
 
36
37
  parsed_command_line = Brut::CLI::ParsedCommandLine.new(app_command: @app_command, argv:, env:)
37
38
 
39
+ logger = Brut::CLI::Logger.new(
40
+ app_name: @app_command.name,
41
+ stdout: @stdout,
42
+ stderr: @stderr,
43
+ theme: parsed_command_line.command.theme,
44
+ )
45
+
38
46
  load_unix_environment!(env, parsed_command_line)
39
47
  setup_log_level(env, parsed_command_line)
40
48
  bootstrap!(env, parsed_command_line)
@@ -46,12 +54,23 @@ class Brut::CLI::Runner
46
54
  env:,
47
55
  stdout: @stdout,
48
56
  stderr: @stderr,
49
- stdin: @stdin
57
+ stdin: @stdin,
58
+ logger:
50
59
  )
51
60
  parsed_command_line.command.execute(execution_context)
52
61
  end
53
62
  execute_result.exit_status do |error_message|
63
+ logger.fatal(error_message)
54
64
  @stderr.puts error_message
65
+ if parsed_command_line.options.log_file && !parsed_command_line.options.log_stdout?
66
+ @stderr.puts
67
+ @stderr.puts "More details may be available from the log file:"
68
+ @stderr.puts
69
+ @stderr.puts " " + parsed_command_line.options.log_file.to_s
70
+ @stderr.puts
71
+ @stderr.puts "You can also use --log-stdout to see these log messages in the terminal"
72
+ end
73
+
55
74
  end
56
75
  end
57
76
 
@@ -77,10 +96,12 @@ private
77
96
  end
78
97
  require "bundler"
79
98
  if rack_env == "production"
99
+ Bundler.setup(:default)
80
100
  Bundler.require(:default)
81
101
  return
82
102
  end
83
103
 
104
+ Bundler.setup(:default, rack_env.to_sym)
84
105
  Bundler.require(:default, rack_env.to_sym)
85
106
 
86
107
  require "dotenv"
@@ -112,6 +133,12 @@ private
112
133
 
113
134
  def bootstrap!(env, parsed_command_line)
114
135
  if env["RACK_ENV"]
136
+ log_level = env["LOG_LEVEL"]
137
+
138
+ if !parsed_command_line.options.verbose? && !parsed_command_line.options.debug?
139
+ env["LOG_LEVEL"] = "warn"
140
+ end
141
+
115
142
  require "#{@project_root}/app/bootstrap"
116
143
  bootstrap = Bootstrap.new
117
144
  if parsed_command_line.command.bootstrap?
@@ -119,6 +146,8 @@ private
119
146
  else
120
147
  bootstrap.configure_only!
121
148
  end
149
+
150
+ env["LOG_LEVEL"] = log_level
122
151
  end
123
152
  end
124
153
  end
@@ -0,0 +1,74 @@
1
+ require "io/console"
2
+ require "timeout"
3
+ require "stringio"
4
+
5
+ # Stores metdata about the current temrinal in use. This should provide any metadata
6
+ # about the terminal that can be reliably determined.
7
+ class Brut::CLI::Terminal
8
+
9
+ def initialize
10
+ trap("WINCH") do
11
+ @winsize = IO.console.winsize
12
+ end
13
+ end
14
+
15
+ # Number of rows for the current terminal. Should be consistent even after a resize
16
+ def rows = winsize[0]
17
+ # Number of columns for the current terminal. Should be consistent even after a resize
18
+ def cols = winsize[1]
19
+
20
+ # The IO used for outputing information to the terminal. Prefer this over `STDOUT`.
21
+ def io = $stdout
22
+
23
+ # The IO to use for requesting input from the user
24
+ def stdin = $stdin
25
+
26
+ # Best attempt to guess the background color of the current terminal.
27
+ # This will not refresh if that color is changed, and its behavior will
28
+ # default to black if determining the color doesn't work or isn't supported.
29
+ def background_color
30
+ @bakground_color ||= begin
31
+ io.write "\e]11;?\a"
32
+ io.flush
33
+
34
+ result = nil
35
+
36
+ begin
37
+ # Read the reply, which should look like:
38
+ # ESC ] 11 ; rgb:0000/0000/0000 BEL
39
+ Timeout.timeout(0.1) do
40
+ buf = +""
41
+ loop do
42
+ ch = stdin.getch
43
+ buf << ch
44
+ break if ch == "\a" || buf.end_with?("\e\\") # BEL or ST terminator
45
+ end
46
+ result = buf
47
+ end
48
+ rescue Timeout::Error
49
+ # no reply within 100ms — terminal probably doesn’t support it
50
+ end
51
+
52
+ rgb = [ 0, 0, 0 ]
53
+ if result
54
+ if result =~ /\e\]11;([^ \a\e]*)[\a\e\\]/
55
+ color = Regexp.last_match(1)
56
+ parts = color[/rgb:(.*)/, 1]&.split("/")
57
+ if parts
58
+
59
+ rgb = parts.map { it.to_i(16) / 0xffff.to_f * 256 }.map(&:to_i)
60
+ end
61
+ end
62
+ end
63
+ rgb
64
+ end
65
+ end
66
+
67
+
68
+ private
69
+
70
+ def winsize
71
+ @winsize ||= IO.console.winsize
72
+ end
73
+
74
+ end
@@ -0,0 +1,131 @@
1
+ require "lipgloss"
2
+ class Brut::CLI::TerminalTheme
3
+ def initialize(terminal:)
4
+ @terminal = terminal
5
+ end
6
+
7
+ def title
8
+ @title ||= Lipgloss::Style.new.bold(true).foreground(white_strong)
9
+ end
10
+ def header
11
+ @header ||= Lipgloss::Style.new.foreground(blue_strong).bold(true)
12
+ end
13
+ def subheader
14
+ @subheader ||= Lipgloss::Style.new.foreground(cyan_strong).italic(true)
15
+ end
16
+ def weak
17
+ @weak ||= Lipgloss::Style.new.faint(true)
18
+ end
19
+ def url
20
+ @url ||= Lipgloss::Style.new.underline(true).bold(true)
21
+ end
22
+ def code
23
+ @code ||= Lipgloss::Style.new.foreground(cyan_strong).bold(true)
24
+ end
25
+ def bullet(n)
26
+ @bullets ||= [
27
+ Lipgloss::Style.new.foreground(yellow_strong).margin_right(1).margin_left(2),
28
+ Lipgloss::Style.new.foreground(purple_strong).margin_right(1),
29
+ Lipgloss::Style.new.foreground(yellow_weak).margin_right(1),
30
+ Lipgloss::Style.new.foreground(purple_weak).margin_right(1),
31
+ ]
32
+ @bullets[n] || none
33
+ end
34
+
35
+ def none
36
+ @none ||= Lipgloss::Style.new
37
+ end
38
+
39
+ def success
40
+ @success ||= Lipgloss::Style.new.foreground(green_weak).bold(true)
41
+ end
42
+
43
+ def exception
44
+ @exception ||= Lipgloss::Style.new.foreground(red_weak)
45
+ end
46
+
47
+ def error
48
+ @error ||= Lipgloss::Style.new.foreground(red_strong).bold(true)
49
+ end
50
+
51
+ def warning
52
+ @warning ||= Lipgloss::Style.new.foreground(yellow_strong).bold(true)
53
+ end
54
+
55
+ def wrap(text, first_indent: true, indent:, max_width: nil, newline: "\n")
56
+ max_width ||= @terminal.cols
57
+ text_width = [ max_width, @terminal.cols ].min - newline.length
58
+ lines = []
59
+ text.split(/\s+/).each do |word|
60
+ current_line = lines.last
61
+ if current_line.nil?
62
+ lines << []
63
+ current_line = lines.last
64
+ end
65
+ if (current_line.join(" ").length + word.length + 1) > (text_width - indent)
66
+ lines << [ word ]
67
+ else
68
+ current_line << word
69
+ end
70
+ end
71
+ prefix = " " * indent
72
+ lines.map.with_index { |line,index|
73
+ if index == 0 && !first_indent
74
+ line.join(" ")
75
+ else
76
+ prefix + line.join(" ")
77
+ end
78
+ }.join(newline)
79
+ end
80
+
81
+ private
82
+
83
+ def black_weak
84
+ @black_weak ||= Lipgloss::AdaptiveColor.new(light: "#6e6e6e", dark: "#3a3a3a")
85
+ end
86
+ def black_strong
87
+ @black_strong ||= Lipgloss::AdaptiveColor.new(light: "#000000", dark: "#5a5a5a")
88
+ end
89
+ def red_weak
90
+ @red_weak ||= Lipgloss::AdaptiveColor.new(light: "#a31515", dark: "#d16969")
91
+ end
92
+ def red_strong
93
+ @red_strong ||= Lipgloss::AdaptiveColor.new(light: "#d40000", dark: "#f44747")
94
+ end
95
+ def green_weak
96
+ @green_weak ||= Lipgloss::AdaptiveColor.new(light: "#2b6a2b", dark: "#6a9955")
97
+ end
98
+ def green_strong
99
+ @green_strong ||= Lipgloss::AdaptiveColor.new(light: "#007f00", dark: "#89d185")
100
+ end
101
+ def yellow_weak
102
+ @yellow_weak ||= Lipgloss::AdaptiveColor.new(light: "#8a6d1d", dark: "#d7ba7d")
103
+ end
104
+ def yellow_strong
105
+ @yellow_strong ||= Lipgloss::AdaptiveColor.new(light: "#b58900", dark: "#ffcc66")
106
+ end
107
+ def blue_weak
108
+ @blue_weak ||= Lipgloss::AdaptiveColor.new(light: "#005f87", dark: "#569cd6")
109
+ end
110
+ def blue_strong
111
+ @blue_strong ||= Lipgloss::AdaptiveColor.new(light: "#0047ab", dark: "#4fc1ff")
112
+ end
113
+ def purple_weak
114
+ @purple_weak ||= Lipgloss::AdaptiveColor.new(light: "#6f42c1", dark: "#c586c0")
115
+ end
116
+ def purple_strong
117
+ @purple_strong ||= Lipgloss::AdaptiveColor.new(light: "#5a2ca0", dark: "#d670d6")
118
+ end
119
+ def cyan_weak
120
+ @cyan_weak ||= Lipgloss::AdaptiveColor.new(light: "#006f6f", dark: "#4ec9b0")
121
+ end
122
+ def cyan_strong
123
+ @cyan_strong ||= Lipgloss::AdaptiveColor.new(light: "#007acc", dark: "#2dd4bf")
124
+ end
125
+ def white_weak
126
+ @white_weak ||= Lipgloss::AdaptiveColor.new(light: "#ffffff", dark: "#cfcfcf")
127
+ end
128
+ def white_strong
129
+ @white_strong ||= Lipgloss::AdaptiveColor.new(light: "#f0f0f0", dark: "#ffffff")
130
+ end
131
+ end
data/lib/brut/cli.rb CHANGED
@@ -16,14 +16,18 @@ module Brut
16
16
  autoload(:ParsedCommandLine, "brut/cli/parsed_command_line")
17
17
  autoload(:Runner, "brut/cli/runner")
18
18
  autoload(:SystemExecError, "brut/cli/error")
19
+ autoload(:Terminal, "brut/cli/terminal")
20
+ autoload(:TerminalTheme, "brut/cli/terminal_theme")
21
+ autoload(:Logger, "brut/cli/logger")
19
22
 
20
23
  # Holds Brut-provided CLI apps that are set up in your project.
21
24
  module Apps
22
- autoload(:DB,"brut/cli/apps/db")
23
- autoload(:Test,"brut/cli/apps/test")
24
25
  autoload(:BuildAssets,"brut/cli/apps/build_assets")
26
+ autoload(:DB,"brut/cli/apps/db")
27
+ autoload(:Deploy,"brut/cli/apps/deploy")
28
+ autoload(:New,"brut/cli/apps/new")
25
29
  autoload(:Scaffold,"brut/cli/apps/scaffold")
26
- autoload(:DeployBase,"brut/cli/apps/deploy_base")
30
+ autoload(:Test,"brut/cli/apps/test")
27
31
  end
28
32
  end
29
33
  end
@@ -358,7 +358,7 @@ private
358
358
  semantic_logger_appenders.each do |appender|
359
359
  SemanticLogger.add_appender(**appender)
360
360
  end
361
- SemanticLogger["Brut"].info("Logging set up")
361
+ SemanticLogger[self.class].debug("Logging set up")
362
362
  end
363
363
 
364
364
  def setup_i18n
@@ -394,10 +394,10 @@ private
394
394
  "db" => "DB"
395
395
  )
396
396
  if Brut.container.auto_reload_classes?
397
- SemanticLogger["Brut"].info("Auto-reloaded configured")
397
+ SemanticLogger[self.class].debug("Auto-reloaded configured")
398
398
  @loader.enable_reloading
399
399
  else
400
- SemanticLogger["Brut"].info("Classes will not be auto-reloaded")
400
+ SemanticLogger[self.class].info("Classes will not be auto-reloaded")
401
401
  end
402
402
 
403
403
  @loader.setup
@@ -424,6 +424,7 @@ private
424
424
 
425
425
  def boot_otel!
426
426
  OpenTelemetry::SDK.configure do |c|
427
+ c.logger = SemanticLogger["OpenTelemetry"]
427
428
  c.service_name = @app.id
428
429
  if ENV["OTEL_TRACES_EXPORTER"]
429
430
  SemanticLogger[self.class].info "OTEL_TRACES_EXPORTER was set (to '#{ENV['OTEL_TRACES_EXPORTER']}'), so Brut's OTel logging is disabled"
@@ -5,20 +5,24 @@ class Brut::FrontEnd::AssetMetadata
5
5
 
6
6
  # @param [String] asset_metadata_file to the asset metadata file
7
7
  # @param [IO] out IO on which to write messaging
8
- def initialize(asset_metadata_file:,out:$stdout)
8
+ def initialize(asset_metadata_file:,logger: :use_default)
9
9
  @asset_metadata_file = asset_metadata_file
10
- @out = out
10
+ @logger = if logger == :use_default
11
+ SemanticLogger[self.class]
12
+ else
13
+ logger
14
+ end
11
15
  @asset_metadata = nil
12
16
  end
13
17
 
14
18
  def merge!(extension:,esbuild_metafile:)
15
- @out.puts "Parsing metafile '#{esbuild_metafile}'"
19
+ @logger.debug "Parsing metafile '#{esbuild_metafile}'"
16
20
  esbuild_metafile = ESBuildMetafile.new(metafile:esbuild_metafile)
17
21
  metadata = esbuild_metafile.parse(extension:)
18
22
  begin
19
23
  self.load!
20
24
  rescue Errno::ENOENT
21
- @out.puts "'#{@asset_metadata_file}' does not exist - creating it"
25
+ @logger.debug "'#{@asset_metadata_file}' does not exist - creating it"
22
26
  @asset_metadata = {}
23
27
  end
24
28
  existing_metadata = @asset_metadata[extension] || {}
@@ -48,7 +52,7 @@ class Brut::FrontEnd::AssetMetadata
48
52
  end
49
53
 
50
54
  def save!
51
- @out.puts "Writing updated asset metadata file '#{@asset_metadata_file}'"
55
+ @logger.info "Writing updated asset metadata file '#{@asset_metadata_file}'"
52
56
  File.open(@asset_metadata_file,"w") do |file|
53
57
  file.puts({ "asset_metadata" => @asset_metadata }.to_json)
54
58
  end
@@ -30,16 +30,22 @@ module Brut::SpecSupport::CLICommandSupport
30
30
  stdin: StringIO.new,
31
31
  stdout: StringIO.new,
32
32
  stderr: StringIO.new,
33
- executor: :default
33
+ executor: :default,
34
+ logger: :default
34
35
  )
36
+ logger = if logger == :default
37
+ Brut::CLI::Logger.new(app_name: $0, stdout:, stderr:)
38
+ else
39
+ logger
40
+ end
35
41
  Brut::CLI::Commands::ExecutionContext.new(
36
42
  argv:,
37
43
  options: Brut::CLI::Options.new({ "log-level": "error" }.merge(options)),
38
- env:,
44
+ env: { "NO_COLOR" => "1" }.merge(env),
39
45
  stdin:,
40
46
  stdout:,
41
47
  stderr:,
42
- executor: executor == :default ? CapturingExecutor.new(out: stdout, err: stderr) : executor,
48
+ executor: executor == :default ? CapturingExecutor.new(out: stdout, err: stderr, logger:) : executor,
43
49
  )
44
50
  end
45
51
  end
@@ -26,8 +26,8 @@ class Brut::SpecSupport::E2ETestServer
26
26
  logger.warn "Server is already running on pid '#{@pid}'"
27
27
  return
28
28
  end
29
+ command = "#{@bin_dir}/test-server"
29
30
  Bundler.with_unbundled_env do
30
- command = "#{@bin_dir}/test-server"
31
31
  logger.info "Starting test server via '#{command}'"
32
32
  @pid = Process.spawn(
33
33
  command,
@@ -39,7 +39,7 @@ class Brut::SpecSupport::E2ETestServer
39
39
  if is_port_open?("0.0.0.0",6503)
40
40
  logger.info "Server is listening for requests on port 6503"
41
41
  else
42
- raise "Problem: server never started"
42
+ raise "Problem: test server never started - noting listening on port 6503 after starting with pid '#{@pid}'"
43
43
  end
44
44
  end
45
45
 
@@ -79,8 +79,8 @@ private
79
79
  sleep(0.1)
80
80
  end
81
81
  end
82
- rescue Timeout::Error
83
82
  end
83
+ rescue Timeout::Error
84
84
  false
85
85
  end
86
86
  end
@@ -2,7 +2,7 @@ require "logger"
2
2
  require "fileutils"
3
3
 
4
4
  # A TUI script is a set of steps that are executed in order. Steps
5
- # can be grouped int phases, and each step can either shell out
5
+ # can be grouped into phases, and each step can either shell out
6
6
  # to an external command or execute Ruby code.
7
7
  #
8
8
  # You are intended to subclass this class and implement `#execute`, which can use
data/lib/brut/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Brut
2
2
  # @!visibility private
3
- VERSION = "0.18.2"
3
+ VERSION = "0.19.0"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brut
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.18.2
4
+ version: 0.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Bryant Copeland
@@ -65,6 +65,20 @@ dependencies:
65
65
  - - ">="
66
66
  - !ruby/object:Gem::Version
67
67
  version: '0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: lipgloss
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
68
82
  - !ruby/object:Gem::Dependency
69
83
  name: nokogiri
70
84
  requirement: !ruby/object:Gem::Requirement
@@ -493,8 +507,6 @@ files:
493
507
  - lib/brut/cli/apps/build_assets.rb
494
508
  - lib/brut/cli/apps/db.rb
495
509
  - lib/brut/cli/apps/deploy.rb
496
- - lib/brut/cli/apps/deploy_base.rb
497
- - lib/brut/cli/apps/heroku_container_based_deploy.rb
498
510
  - lib/brut/cli/apps/new.rb
499
511
  - lib/brut/cli/apps/new/add_segment.rb
500
512
  - lib/brut/cli/apps/new/add_segment_options.rb
@@ -541,10 +553,13 @@ files:
541
553
  - lib/brut/cli/error.rb
542
554
  - lib/brut/cli/execute_result.rb
543
555
  - lib/brut/cli/executor.rb
556
+ - lib/brut/cli/logger.rb
544
557
  - lib/brut/cli/options.rb
545
558
  - lib/brut/cli/output.rb
546
559
  - lib/brut/cli/parsed_command_line.rb
547
560
  - lib/brut/cli/runner.rb
561
+ - lib/brut/cli/terminal.rb
562
+ - lib/brut/cli/terminal_theme.rb
548
563
  - lib/brut/factory_bot.rb
549
564
  - lib/brut/framework.rb
550
565
  - lib/brut/framework/app.rb
@@ -802,7 +817,6 @@ files:
802
817
  - templates/segments/Demo/specs/front_end/pages/guestbook_page.spec.rb
803
818
  - templates/segments/Demo/specs/front_end/pages/guestbook_page/message_component.spec.rb
804
819
  - templates/segments/Demo/specs/front_end/pages/new_guestbook_message_page.spec.rb
805
- - templates/segments/Heroku/bin/deploy
806
820
  - templates/segments/Heroku/deploy/Dockerfile
807
821
  - templates/segments/Heroku/deploy/docker-entrypoint
808
822
  - templates/segments/Heroku/deploy/docker_config.rb