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.
- checksums.yaml +4 -4
- data/lib/brut/cli/apps/build_assets.rb +63 -32
- data/lib/brut/cli/apps/db.rb +198 -78
- data/lib/brut/cli/apps/deploy.rb +215 -140
- data/lib/brut/cli/apps/new/app.rb +127 -41
- data/lib/brut/cli/apps/scaffold.rb +108 -105
- data/lib/brut/cli/apps/test.rb +45 -26
- data/lib/brut/cli/commands/base_command.rb +58 -22
- data/lib/brut/cli/commands/compound_command.rb +2 -4
- data/lib/brut/cli/commands/execution_context.rb +17 -10
- data/lib/brut/cli/commands/help.rb +112 -6
- data/lib/brut/cli/commands/output_error.rb +1 -1
- data/lib/brut/cli/execute_result.rb +4 -0
- data/lib/brut/cli/executor.rb +7 -7
- data/lib/brut/cli/logger.rb +122 -0
- data/lib/brut/cli/output.rb +9 -45
- data/lib/brut/cli/parsed_command_line.rb +33 -10
- data/lib/brut/cli/runner.rb +37 -8
- data/lib/brut/cli/terminal.rb +74 -0
- data/lib/brut/cli/terminal_theme.rb +131 -0
- data/lib/brut/cli.rb +7 -3
- data/lib/brut/framework/mcp.rb +4 -3
- data/lib/brut/front_end/asset_metadata.rb +9 -5
- data/lib/brut/spec_support/cli_command_support.rb +9 -3
- data/lib/brut/spec_support/e2e_test_server.rb +3 -3
- data/lib/brut/tui/script.rb +1 -1
- data/lib/brut/version.rb +1 -1
- metadata +18 -4
- data/lib/brut/cli/apps/deploy_base.rb +0 -86
- data/lib/brut/cli/apps/heroku_container_based_deploy.rb +0 -226
- data/templates/segments/Heroku/bin/deploy +0 -11
|
@@ -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
|
data/lib/brut/cli/runner.rb
CHANGED
|
@@ -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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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 =
|
|
21
|
-
@stderr =
|
|
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(:
|
|
30
|
+
autoload(:Test,"brut/cli/apps/test")
|
|
27
31
|
end
|
|
28
32
|
end
|
|
29
33
|
end
|
data/lib/brut/framework/mcp.rb
CHANGED
|
@@ -358,7 +358,7 @@ private
|
|
|
358
358
|
semantic_logger_appenders.each do |appender|
|
|
359
359
|
SemanticLogger.add_appender(**appender)
|
|
360
360
|
end
|
|
361
|
-
SemanticLogger[
|
|
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[
|
|
397
|
+
SemanticLogger[self.class].debug("Auto-reloaded configured")
|
|
398
398
|
@loader.enable_reloading
|
|
399
399
|
else
|
|
400
|
-
SemanticLogger[
|
|
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:,
|
|
8
|
+
def initialize(asset_metadata_file:,logger: :use_default)
|
|
9
9
|
@asset_metadata_file = asset_metadata_file
|
|
10
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
data/lib/brut/tui/script.rb
CHANGED
|
@@ -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
|
|
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
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.
|
|
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
|