howzit 2.1.28 → 2.1.30
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/CHANGELOG.md +121 -0
- data/README.md +5 -1
- data/Rakefile +11 -4
- data/bin/howzit +65 -65
- data/howzit.gemspec +1 -1
- data/lib/howzit/buildnote.rb +4 -8
- data/lib/howzit/colors.rb +50 -22
- data/lib/howzit/condition_evaluator.rb +307 -0
- data/lib/howzit/conditional_content.rb +96 -0
- data/lib/howzit/config.rb +28 -3
- data/lib/howzit/console_logger.rb +74 -2
- data/lib/howzit/directive.rb +137 -0
- data/lib/howzit/prompt.rb +20 -12
- data/lib/howzit/run_report.rb +1 -1
- data/lib/howzit/script_comm.rb +105 -0
- data/lib/howzit/script_support.rb +479 -0
- data/lib/howzit/stringutils.rb +4 -4
- data/lib/howzit/task.rb +68 -6
- data/lib/howzit/topic.rb +576 -13
- data/lib/howzit/util.rb +11 -3
- data/lib/howzit/version.rb +1 -1
- data/lib/howzit.rb +5 -0
- data/spec/condition_evaluator_spec.rb +261 -0
- data/spec/conditional_blocks_integration_spec.rb +159 -0
- data/spec/conditional_content_spec.rb +296 -0
- data/spec/log_level_spec.rb +247 -0
- data/spec/script_comm_spec.rb +303 -0
- data/spec/sequential_conditional_spec.rb +319 -0
- data/spec/set_var_spec.rb +603 -0
- data/spec/spec_helper.rb +3 -1
- data/spec/topic_spec.rb +8 -6
- data/src/_README.md +5 -1
- metadata +23 -4
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'shellwords'
|
|
5
|
+
|
|
6
|
+
module Howzit
|
|
7
|
+
# Script Support module
|
|
8
|
+
# Handles helper script installation and injection for run blocks
|
|
9
|
+
# rubocop:disable Metrics/ModuleLength
|
|
10
|
+
module ScriptSupport
|
|
11
|
+
SUPPORT_DIR = '~/.local/share/howzit/support'
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
##
|
|
15
|
+
## Get the support directory path
|
|
16
|
+
##
|
|
17
|
+
## @return [String] expanded path to support directory
|
|
18
|
+
##
|
|
19
|
+
def support_dir
|
|
20
|
+
File.expand_path(SUPPORT_DIR)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
##
|
|
24
|
+
## Ensure support directory exists and is populated
|
|
25
|
+
##
|
|
26
|
+
def ensure_support_dir
|
|
27
|
+
dir = support_dir
|
|
28
|
+
FileUtils.mkdir_p(dir) unless File.directory?(dir)
|
|
29
|
+
install_helper_scripts
|
|
30
|
+
dir
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
##
|
|
34
|
+
## Detect interpreter from hashbang line
|
|
35
|
+
##
|
|
36
|
+
## @param script_content [String] The script content
|
|
37
|
+
##
|
|
38
|
+
## @return [Symbol, nil] Language identifier (:bash, :zsh, :fish, :ruby, :python, etc.)
|
|
39
|
+
##
|
|
40
|
+
def detect_interpreter(script_content)
|
|
41
|
+
first_line = script_content.lines.first&.strip
|
|
42
|
+
return nil unless first_line&.start_with?('#!')
|
|
43
|
+
|
|
44
|
+
shebang = first_line.sub(/^#!/, '').strip
|
|
45
|
+
|
|
46
|
+
case shebang
|
|
47
|
+
when %r{/bin/bash}, %r{/usr/bin/env bash}
|
|
48
|
+
:bash
|
|
49
|
+
when %r{/bin/zsh}, %r{/usr/bin/env zsh}
|
|
50
|
+
:zsh
|
|
51
|
+
when %r{/bin/fish}, %r{/usr/bin/env fish}
|
|
52
|
+
:fish
|
|
53
|
+
when %r{/usr/bin/env ruby}, %r{/usr/bin/ruby}, %r{/usr/local/bin/ruby}
|
|
54
|
+
:ruby
|
|
55
|
+
when %r{/usr/bin/env python3?}, %r{/usr/bin/python3?}, %r{/usr/local/bin/python3?}
|
|
56
|
+
:python
|
|
57
|
+
when %r{/usr/bin/env perl}, %r{/usr/bin/perl}
|
|
58
|
+
:perl
|
|
59
|
+
when %r{/usr/bin/env node}, %r{/usr/bin/node}
|
|
60
|
+
:node
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
##
|
|
65
|
+
## Get the injection line for a given interpreter
|
|
66
|
+
##
|
|
67
|
+
## @param interpreter [Symbol] The interpreter type
|
|
68
|
+
##
|
|
69
|
+
## @return [String, nil] The injection line to add
|
|
70
|
+
##
|
|
71
|
+
def injection_line_for(interpreter)
|
|
72
|
+
support_path = support_dir
|
|
73
|
+
case interpreter
|
|
74
|
+
when :bash, :zsh
|
|
75
|
+
"source \"#{support_path}/howzit.sh\""
|
|
76
|
+
when :fish
|
|
77
|
+
"source \"#{support_path}/howzit.fish\""
|
|
78
|
+
when :ruby
|
|
79
|
+
"require '#{support_path}/howzit.rb'"
|
|
80
|
+
when :python
|
|
81
|
+
"import sys\nsys.path.insert(0, '#{support_path}')\nimport howzit"
|
|
82
|
+
when :perl
|
|
83
|
+
"require '#{support_path}/howzit.pl'"
|
|
84
|
+
when :node
|
|
85
|
+
"require('#{support_path}/howzit.js')"
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
##
|
|
90
|
+
## Inject helper script loading into script content
|
|
91
|
+
##
|
|
92
|
+
## @param script_content [String] The original script content
|
|
93
|
+
##
|
|
94
|
+
## @return [Array] [modified_content, interpreter] Script content with injection added and interpreter
|
|
95
|
+
##
|
|
96
|
+
def inject_helper(script_content)
|
|
97
|
+
interpreter = detect_interpreter(script_content)
|
|
98
|
+
return [script_content, nil] unless interpreter
|
|
99
|
+
|
|
100
|
+
injection = injection_line_for(interpreter)
|
|
101
|
+
return [script_content, interpreter] unless injection
|
|
102
|
+
|
|
103
|
+
lines = script_content.lines
|
|
104
|
+
injection_lines = injection.split("\n").map { |l| "#{l}\n" }
|
|
105
|
+
# Find the hashbang line
|
|
106
|
+
if lines.first&.strip&.start_with?('#!')
|
|
107
|
+
# Insert after hashbang
|
|
108
|
+
injection_lines.each_with_index do |line, idx|
|
|
109
|
+
lines.insert(1 + idx, line)
|
|
110
|
+
end
|
|
111
|
+
else
|
|
112
|
+
# No hashbang, prepend
|
|
113
|
+
lines = injection_lines + lines
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
[lines.join, interpreter]
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
##
|
|
120
|
+
## Get the command to execute a script based on interpreter
|
|
121
|
+
##
|
|
122
|
+
## @param script_path [String] Path to the script file
|
|
123
|
+
## @param interpreter [Symbol, nil] The interpreter type
|
|
124
|
+
##
|
|
125
|
+
## @return [String] Command to execute the script
|
|
126
|
+
##
|
|
127
|
+
def execution_command_for(script_path, interpreter)
|
|
128
|
+
cmd = case interpreter
|
|
129
|
+
when :bash
|
|
130
|
+
"/bin/bash #{Shellwords.escape(script_path)}"
|
|
131
|
+
when :zsh
|
|
132
|
+
"/bin/zsh #{Shellwords.escape(script_path)}"
|
|
133
|
+
when :fish
|
|
134
|
+
"/usr/bin/env fish #{Shellwords.escape(script_path)}"
|
|
135
|
+
when :ruby
|
|
136
|
+
"/usr/bin/env ruby #{Shellwords.escape(script_path)}"
|
|
137
|
+
when :python
|
|
138
|
+
"/usr/bin/env python3 #{Shellwords.escape(script_path)}"
|
|
139
|
+
when :perl
|
|
140
|
+
"/usr/bin/env perl #{Shellwords.escape(script_path)}"
|
|
141
|
+
when :node
|
|
142
|
+
"/usr/bin/env node #{Shellwords.escape(script_path)}"
|
|
143
|
+
end
|
|
144
|
+
# Fallback to direct execution if interpreter not recognized
|
|
145
|
+
cmd || script_path
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
##
|
|
149
|
+
## Install all helper scripts
|
|
150
|
+
##
|
|
151
|
+
def install_helper_scripts
|
|
152
|
+
dir = support_dir
|
|
153
|
+
FileUtils.mkdir_p(dir)
|
|
154
|
+
|
|
155
|
+
install_bash_helper(dir)
|
|
156
|
+
install_fish_helper(dir)
|
|
157
|
+
install_ruby_helper(dir)
|
|
158
|
+
install_python_helper(dir)
|
|
159
|
+
install_perl_helper(dir)
|
|
160
|
+
install_node_helper(dir)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
private
|
|
164
|
+
|
|
165
|
+
##
|
|
166
|
+
## Install bash/zsh helper script
|
|
167
|
+
##
|
|
168
|
+
def install_bash_helper(dir)
|
|
169
|
+
file = File.join(dir, 'howzit.sh')
|
|
170
|
+
return if File.exist?(file) && !file_stale?(file)
|
|
171
|
+
|
|
172
|
+
content = <<~BASH
|
|
173
|
+
#!/bin/bash
|
|
174
|
+
# Howzit helper functions for bash/zsh
|
|
175
|
+
|
|
176
|
+
# Log functions
|
|
177
|
+
log() {
|
|
178
|
+
local level="$1"
|
|
179
|
+
shift
|
|
180
|
+
local message="$*"
|
|
181
|
+
if [ -n "$HOWZIT_COMM_FILE" ]; then
|
|
182
|
+
echo "LOG:$level:$message" >> "$HOWZIT_COMM_FILE"
|
|
183
|
+
fi
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
log_info() { log info "$@"; }
|
|
187
|
+
log_warn() { log warn "$@"; }
|
|
188
|
+
log_error() { log error "$@"; }
|
|
189
|
+
log_debug() { log debug "$@"; }
|
|
190
|
+
|
|
191
|
+
# Set variable function
|
|
192
|
+
set_var() {
|
|
193
|
+
local var_name="$1"
|
|
194
|
+
local var_value="$2"
|
|
195
|
+
if [ -n "$HOWZIT_COMM_FILE" ]; then
|
|
196
|
+
echo "VAR:$var_name=$var_value" >> "$HOWZIT_COMM_FILE"
|
|
197
|
+
fi
|
|
198
|
+
}
|
|
199
|
+
BASH
|
|
200
|
+
|
|
201
|
+
File.write(file, content)
|
|
202
|
+
File.chmod(0o644, file)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
##
|
|
206
|
+
## Install fish helper script
|
|
207
|
+
##
|
|
208
|
+
def install_fish_helper(dir)
|
|
209
|
+
file = File.join(dir, 'howzit.fish')
|
|
210
|
+
return if File.exist?(file) && !file_stale?(file)
|
|
211
|
+
|
|
212
|
+
content = <<~FISH
|
|
213
|
+
#!/usr/bin/env fish
|
|
214
|
+
# Howzit helper functions for fish
|
|
215
|
+
|
|
216
|
+
function log -d "Log a message at the specified level"
|
|
217
|
+
set level $argv[1]
|
|
218
|
+
set -e argv[1]
|
|
219
|
+
set message (string join " " $argv)
|
|
220
|
+
if test -n "$HOWZIT_COMM_FILE"
|
|
221
|
+
echo "LOG:$level:$message" >> "$HOWZIT_COMM_FILE"
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
function log_info -d "Log an info message"
|
|
226
|
+
log info $argv
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
function log_warn -d "Log a warning message"
|
|
230
|
+
log warn $argv
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
function log_error -d "Log an error message"
|
|
234
|
+
log error $argv
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
function log_debug -d "Log a debug message"
|
|
238
|
+
log debug $argv
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
function set_var -d "Set a variable for howzit"
|
|
242
|
+
set var_name $argv[1]
|
|
243
|
+
set var_value $argv[2]
|
|
244
|
+
if test -n "$HOWZIT_COMM_FILE"
|
|
245
|
+
echo "VAR:$var_name=$var_value" >> "$HOWZIT_COMM_FILE"
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
FISH
|
|
249
|
+
|
|
250
|
+
File.write(file, content)
|
|
251
|
+
File.chmod(0o644, file)
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
##
|
|
255
|
+
## Install Ruby helper script
|
|
256
|
+
##
|
|
257
|
+
def install_ruby_helper(dir)
|
|
258
|
+
file = File.join(dir, 'howzit.rb')
|
|
259
|
+
return if File.exist?(file) && !file_stale?(file)
|
|
260
|
+
|
|
261
|
+
content = <<~'RUBY'
|
|
262
|
+
# frozen_string_literal: true
|
|
263
|
+
|
|
264
|
+
# Howzit helper module for Ruby
|
|
265
|
+
module Howzit
|
|
266
|
+
class << self
|
|
267
|
+
# Log methods
|
|
268
|
+
def logger
|
|
269
|
+
@logger ||= Logger.new
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
class Logger
|
|
273
|
+
def info(message)
|
|
274
|
+
log(:info, message)
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def warn(message)
|
|
278
|
+
log(:warn, message)
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def error(message)
|
|
282
|
+
log(:error, message)
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
def debug(message)
|
|
286
|
+
log(:debug, message)
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
private
|
|
290
|
+
|
|
291
|
+
def log(level, message)
|
|
292
|
+
comm_file = ENV['HOWZIT_COMM_FILE']
|
|
293
|
+
return unless comm_file
|
|
294
|
+
|
|
295
|
+
File.open(comm_file, 'a') do |f|
|
|
296
|
+
f.puts "LOG:#{level}:#{message}"
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# Set variable method
|
|
302
|
+
def set_var(name, value)
|
|
303
|
+
comm_file = ENV['HOWZIT_COMM_FILE']
|
|
304
|
+
return unless comm_file
|
|
305
|
+
|
|
306
|
+
File.open(comm_file, 'a') do |f|
|
|
307
|
+
f.puts "VAR:#{name}=#{value}"
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
RUBY
|
|
313
|
+
|
|
314
|
+
File.write(file, content)
|
|
315
|
+
File.chmod(0o644, file)
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
##
|
|
319
|
+
## Install Python helper script
|
|
320
|
+
##
|
|
321
|
+
def install_python_helper(dir)
|
|
322
|
+
file = File.join(dir, 'howzit.py')
|
|
323
|
+
return if File.exist?(file) && !file_stale?(file)
|
|
324
|
+
|
|
325
|
+
content = <<~PYTHON
|
|
326
|
+
#!/usr/bin/env python3
|
|
327
|
+
# Howzit helper module for Python
|
|
328
|
+
|
|
329
|
+
import os
|
|
330
|
+
|
|
331
|
+
class _Logger:
|
|
332
|
+
def _log(self, level, message):
|
|
333
|
+
comm_file = os.environ.get('HOWZIT_COMM_FILE')
|
|
334
|
+
if comm_file:
|
|
335
|
+
with open(comm_file, 'a') as f:
|
|
336
|
+
f.write(f"LOG:{level}:{message}\\n")
|
|
337
|
+
|
|
338
|
+
def info(self, message):
|
|
339
|
+
self._log('info', message)
|
|
340
|
+
|
|
341
|
+
def warn(self, message):
|
|
342
|
+
self._log('warn', message)
|
|
343
|
+
|
|
344
|
+
def error(self, message):
|
|
345
|
+
self._log('error', message)
|
|
346
|
+
|
|
347
|
+
def debug(self, message):
|
|
348
|
+
self._log('debug', message)
|
|
349
|
+
|
|
350
|
+
class Howzit:
|
|
351
|
+
logger = _Logger()
|
|
352
|
+
|
|
353
|
+
@staticmethod
|
|
354
|
+
def set_var(name, value):
|
|
355
|
+
comm_file = os.environ.get('HOWZIT_COMM_FILE')
|
|
356
|
+
if comm_file:
|
|
357
|
+
with open(comm_file, 'a') as f:
|
|
358
|
+
f.write(f"VAR:{name}={value}\\n")
|
|
359
|
+
PYTHON
|
|
360
|
+
|
|
361
|
+
File.write(file, content)
|
|
362
|
+
File.chmod(0o644, file)
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
##
|
|
366
|
+
## Install Perl helper script
|
|
367
|
+
##
|
|
368
|
+
def install_perl_helper(dir)
|
|
369
|
+
file = File.join(dir, 'howzit.pl')
|
|
370
|
+
return if File.exist?(file) && !file_stale?(file)
|
|
371
|
+
|
|
372
|
+
content = <<~PERL
|
|
373
|
+
#!/usr/bin/env perl
|
|
374
|
+
# Howzit helper module for Perl
|
|
375
|
+
|
|
376
|
+
package Howzit;
|
|
377
|
+
|
|
378
|
+
use strict;
|
|
379
|
+
use warnings;
|
|
380
|
+
|
|
381
|
+
sub log {
|
|
382
|
+
my ($level, $message) = @_;
|
|
383
|
+
my $comm_file = $ENV{'HOWZIT_COMM_FILE'};
|
|
384
|
+
return unless $comm_file;
|
|
385
|
+
|
|
386
|
+
open(my $fh, '>>', $comm_file) or return;
|
|
387
|
+
print $fh "LOG:$level:$message\\n";
|
|
388
|
+
close($fh);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
sub log_info { log('info', $_[0]); }
|
|
392
|
+
sub log_warn { log('warn', $_[0]); }
|
|
393
|
+
sub log_error { log('error', $_[0]); }
|
|
394
|
+
sub log_debug { log('debug', $_[0]); }
|
|
395
|
+
|
|
396
|
+
sub set_var {
|
|
397
|
+
my ($name, $value) = @_;
|
|
398
|
+
my $comm_file = $ENV{'HOWZIT_COMM_FILE'};
|
|
399
|
+
return unless $comm_file;
|
|
400
|
+
|
|
401
|
+
open(my $fh, '>>', $comm_file) or return;
|
|
402
|
+
print $fh "VAR:$name=$value\\n";
|
|
403
|
+
close($fh);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
1;
|
|
407
|
+
PERL
|
|
408
|
+
|
|
409
|
+
File.write(file, content)
|
|
410
|
+
File.chmod(0o644, file)
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
##
|
|
414
|
+
## Install Node.js helper script
|
|
415
|
+
##
|
|
416
|
+
def install_node_helper(dir)
|
|
417
|
+
file = File.join(dir, 'howzit.js')
|
|
418
|
+
return if File.exist?(file) && !file_stale?(file)
|
|
419
|
+
|
|
420
|
+
content = <<~JAVASCRIPT
|
|
421
|
+
// Howzit helper module for Node.js
|
|
422
|
+
|
|
423
|
+
const fs = require('fs');
|
|
424
|
+
const path = require('path');
|
|
425
|
+
|
|
426
|
+
class Logger {
|
|
427
|
+
_log(level, message) {
|
|
428
|
+
const commFile = process.env.HOWZIT_COMM_FILE;
|
|
429
|
+
if (commFile) {
|
|
430
|
+
fs.appendFileSync(commFile, `LOG:${level}:${message}\\n`);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
info(message) {
|
|
435
|
+
this._log('info', message);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
warn(message) {
|
|
439
|
+
this._log('warn', message);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
error(message) {
|
|
443
|
+
this._log('error', message);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
debug(message) {
|
|
447
|
+
this._log('debug', message);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
class Howzit {
|
|
452
|
+
static logger = new Logger();
|
|
453
|
+
|
|
454
|
+
static setVar(name, value) {
|
|
455
|
+
const commFile = process.env.HOWZIT_COMM_FILE;
|
|
456
|
+
if (commFile) {
|
|
457
|
+
fs.appendFileSync(commFile, `VAR:${name}=${value}\\n`);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
module.exports = { Howzit, Logger };
|
|
463
|
+
JAVASCRIPT
|
|
464
|
+
|
|
465
|
+
File.write(file, content)
|
|
466
|
+
File.chmod(0o644, file)
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
##
|
|
470
|
+
## Check if a file is stale and needs updating
|
|
471
|
+
## For now, always update to ensure latest version
|
|
472
|
+
##
|
|
473
|
+
def file_stale?(_file)
|
|
474
|
+
true
|
|
475
|
+
end
|
|
476
|
+
end
|
|
477
|
+
# rubocop:enable Metrics/ModuleLength
|
|
478
|
+
end
|
|
479
|
+
end
|
data/lib/howzit/stringutils.rb
CHANGED
|
@@ -38,7 +38,7 @@ module Howzit
|
|
|
38
38
|
position = 0
|
|
39
39
|
in_order = 0
|
|
40
40
|
chars.each do |char|
|
|
41
|
-
new_pos = self[position
|
|
41
|
+
new_pos = self[position..] =~ /#{char}/i
|
|
42
42
|
if new_pos
|
|
43
43
|
position += new_pos
|
|
44
44
|
in_order += 1
|
|
@@ -72,7 +72,7 @@ module Howzit
|
|
|
72
72
|
##
|
|
73
73
|
def distance(chars)
|
|
74
74
|
distance = 0
|
|
75
|
-
max =
|
|
75
|
+
max = length - chars.length
|
|
76
76
|
return max unless in_order(chars) == chars.length
|
|
77
77
|
|
|
78
78
|
while distance < max
|
|
@@ -219,7 +219,7 @@ module Howzit
|
|
|
219
219
|
def uncolor
|
|
220
220
|
# force UTF-8 and remove invalid characters, then remove color codes
|
|
221
221
|
# and iTerm markers
|
|
222
|
-
gsub(Howzit::Color::COLORED_REGEXP,
|
|
222
|
+
gsub(Howzit::Color::COLORED_REGEXP, '').gsub(/\e\]1337;SetMark/, '')
|
|
223
223
|
end
|
|
224
224
|
|
|
225
225
|
# Wrap text at a specified width.
|
|
@@ -371,7 +371,7 @@ module Howzit
|
|
|
371
371
|
gsub!(/\$\{(?<name>[A-Z0-9_]+(?::.*?)?)\}/i) do
|
|
372
372
|
m = Regexp.last_match
|
|
373
373
|
arg, default = m['name'].split(/:/).map(&:strip)
|
|
374
|
-
if Howzit.named_arguments
|
|
374
|
+
if Howzit.named_arguments&.key?(arg) && !Howzit.named_arguments[arg].nil?
|
|
375
375
|
Howzit.named_arguments[arg]
|
|
376
376
|
elsif default
|
|
377
377
|
default
|
data/lib/howzit/task.rb
CHANGED
|
@@ -5,7 +5,7 @@ require 'English'
|
|
|
5
5
|
module Howzit
|
|
6
6
|
# Task object
|
|
7
7
|
class Task
|
|
8
|
-
attr_reader :type, :title, :action, :arguments, :parent, :optional, :default, :last_status
|
|
8
|
+
attr_reader :type, :title, :action, :arguments, :parent, :optional, :default, :last_status, :log_level
|
|
9
9
|
|
|
10
10
|
##
|
|
11
11
|
## Initialize a Task object
|
|
@@ -20,16 +20,18 @@ module Howzit
|
|
|
20
20
|
## @option attributes :title [String] task title
|
|
21
21
|
## @option attributes :action [String] task action
|
|
22
22
|
## @option attributes :parent [String] title of nested (included) topic origin
|
|
23
|
+
## @option attributes :log_level [String] log level for this task (debug, info, warn, error)
|
|
23
24
|
def initialize(attributes, optional: false, default: true)
|
|
24
25
|
@prefix = "{bw}\u{25B7}\u{25B7} {x}"
|
|
25
26
|
# arrow = "{bw}\u{279F}{x}"
|
|
26
27
|
@arguments = attributes[:arguments] || []
|
|
27
28
|
|
|
28
29
|
@type = attributes[:type] || :run
|
|
29
|
-
@title = attributes[:title]
|
|
30
|
+
@title = attributes[:title]&.to_s
|
|
30
31
|
@parent = attributes[:parent] || nil
|
|
31
32
|
|
|
32
33
|
@action = attributes[:action].render_arguments || nil
|
|
34
|
+
@log_level = attributes[:log_level]
|
|
33
35
|
|
|
34
36
|
@optional = optional
|
|
35
37
|
@default = default
|
|
@@ -61,14 +63,34 @@ module Howzit
|
|
|
61
63
|
Howzit.console.info "#{@prefix}{bg}Running block {bw}#{@title}{x}".c if Howzit.options[:log_level] < 2
|
|
62
64
|
block = @action
|
|
63
65
|
script = Tempfile.new('howzit_script')
|
|
66
|
+
comm_file = ScriptComm.setup
|
|
67
|
+
old_log_level = apply_log_level
|
|
64
68
|
begin
|
|
65
|
-
|
|
69
|
+
# Ensure support directory exists and install helpers
|
|
70
|
+
ScriptSupport.ensure_support_dir
|
|
71
|
+
ENV['HOWZIT_SUPPORT_DIR'] = ScriptSupport.support_dir
|
|
72
|
+
|
|
73
|
+
# Inject helper script loading
|
|
74
|
+
modified_block, interpreter = ScriptSupport.inject_helper(block)
|
|
75
|
+
|
|
76
|
+
script.write(modified_block)
|
|
66
77
|
script.close
|
|
67
|
-
File.chmod(
|
|
68
|
-
|
|
78
|
+
File.chmod(0o755, script.path)
|
|
79
|
+
|
|
80
|
+
# Use appropriate interpreter command
|
|
81
|
+
cmd = ScriptSupport.execution_command_for(script.path, interpreter)
|
|
82
|
+
# If interpreter is nil, execute directly (will respect hashbang)
|
|
83
|
+
res = if interpreter.nil?
|
|
84
|
+
system(script.path)
|
|
85
|
+
else
|
|
86
|
+
system(cmd)
|
|
87
|
+
end
|
|
69
88
|
ensure
|
|
89
|
+
restore_log_level(old_log_level) if old_log_level
|
|
70
90
|
script.close
|
|
71
91
|
script.unlink
|
|
92
|
+
# Process script communication
|
|
93
|
+
ScriptComm.apply(comm_file) if comm_file
|
|
72
94
|
end
|
|
73
95
|
|
|
74
96
|
update_last_status(res ? 0 : 1)
|
|
@@ -94,6 +116,38 @@ module Howzit
|
|
|
94
116
|
[output, matches[0].tasks.count]
|
|
95
117
|
end
|
|
96
118
|
|
|
119
|
+
##
|
|
120
|
+
## Apply log level for this task
|
|
121
|
+
##
|
|
122
|
+
def apply_log_level
|
|
123
|
+
return unless @log_level
|
|
124
|
+
|
|
125
|
+
level_map = {
|
|
126
|
+
'debug' => 0,
|
|
127
|
+
'info' => 1,
|
|
128
|
+
'warn' => 2,
|
|
129
|
+
'warning' => 2,
|
|
130
|
+
'error' => 3
|
|
131
|
+
}
|
|
132
|
+
level_value = level_map[@log_level.downcase] || @log_level.to_i
|
|
133
|
+
old_level = Howzit.options[:log_level]
|
|
134
|
+
Howzit.options[:log_level] = level_value
|
|
135
|
+
Howzit.console.log_level = level_value
|
|
136
|
+
ENV['HOWZIT_LOG_LEVEL'] = @log_level.downcase
|
|
137
|
+
old_level
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
##
|
|
141
|
+
## Restore log level after task execution
|
|
142
|
+
##
|
|
143
|
+
def restore_log_level(old_level)
|
|
144
|
+
return unless @log_level
|
|
145
|
+
|
|
146
|
+
Howzit.options[:log_level] = old_level
|
|
147
|
+
Howzit.console.log_level = old_level
|
|
148
|
+
ENV.delete('HOWZIT_LOG_LEVEL')
|
|
149
|
+
end
|
|
150
|
+
|
|
97
151
|
##
|
|
98
152
|
## Execute a run task
|
|
99
153
|
##
|
|
@@ -112,7 +166,15 @@ module Howzit
|
|
|
112
166
|
end
|
|
113
167
|
Howzit.console.info("#{@prefix}{bg}Running {bw}#{display_title}{x}".c)
|
|
114
168
|
ENV['HOWZIT_SCRIPTS'] = File.expand_path('~/.config/howzit/scripts')
|
|
115
|
-
|
|
169
|
+
comm_file = ScriptComm.setup
|
|
170
|
+
old_log_level = apply_log_level
|
|
171
|
+
begin
|
|
172
|
+
res = system(@action)
|
|
173
|
+
ensure
|
|
174
|
+
restore_log_level(old_log_level) if old_log_level
|
|
175
|
+
# Process script communication
|
|
176
|
+
ScriptComm.apply(comm_file) if comm_file
|
|
177
|
+
end
|
|
116
178
|
update_last_status(res ? 0 : 1)
|
|
117
179
|
res
|
|
118
180
|
end
|