markdown_exec 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7ec074d1854ef0150cf60852fd39d7db7bc88461f7d9f5ae6547fe009142ffb4
4
- data.tar.gz: 8d6eb3c7759bf180b996f8a68ec8b52d0e52a230365b163f06528e9c11627e42
3
+ metadata.gz: 2336bb2091df5bf018181e832fb9c5e7a5b7ee542b6f71cde38a3afb3aa88ab4
4
+ data.tar.gz: '072654942ddf5897784c71724a7f9fa6fb5bea9b395d54ca18a3f3fd9b02c5af'
5
5
  SHA512:
6
- metadata.gz: '095584193734695c29729060ca4ccd424088ca59cdd8bf539dda5a6b914d7fd71d373304f071e46b49072bf01b09ae2a1f0cf86bf314f3d79ace9acd166a3531'
7
- data.tar.gz: c8e55fa064fe9bc8c170c9431dd1a5dc9fd3f20f1fe42925c00c4f2ed5113d597f457ecdba225cf4533563cd0c3f14f35ebc1ad096e8a89f8ec654a5cd87cd8c
6
+ metadata.gz: 2f28a18aea943a7fec92b16d232b8c3722a30f6960fbd32bf84e95762b4ac322f0fb53f75563118a15136da72e49f16c580a8c7fbf05d2001857e068403834ef
7
+ data.tar.gz: 8bb762715d790e37906d61cf8834e86dfe7e4f9611b8f7477da508d2ff658d496c6e1e0c89fc42e9e5f2cf937e29dae3cddf062cabda867f3a5bb1466986f2c3
data/CHANGELOG.md CHANGED
@@ -1,37 +1,30 @@
1
1
  # Changelog
2
2
 
3
- ## [ToDo]
4
3
 
5
- - pipe stdin to script
6
- - yes/no/write/clipboard/record/edit/history
7
- - add confirm block to generated file
8
- - present timestamp, result of last exec for each command
9
- - user settings
10
- - hidden w , w/o () in names
11
- - exit in menus
12
- - fix regexp in pathnames
13
- - tab completion from md file
14
- - read file once to allow for tempdoc stream
15
- - include md or blocks file
4
+ ## [0.2.4] - 2022-04-01
16
5
 
17
- - tree display
18
-
19
- - mde options in md file or included file
20
-
21
- - include blocks from local md file
22
-
23
- - save outputs, errors
6
+ ### Added
24
7
 
25
- - chmod a+x logged script
8
+ - Command `--list-recent-scripts` to list the last *N* saved scripts.
9
+ - Command `--run-last-script` to re-run the last saved script.
10
+ - Command `--select-recent-script` to select and execute a recently saved script.
26
11
 
27
- - exec most recent logged scripts
12
+ | YAML Name | Environment Variable | Option Name | Default | Purpose |
13
+ | :--- | :--- | :--- | :--- | :--- |
14
+ | list_count | MDE_LIST_COUNT | `--list_count` | `16` | Max. items to return in list |
15
+ | logged_stdout_filename_prefix | MDE_LOGGED_STDOUT_FILENAME_PREFIX | | `mde` | Name prefix for stdout files |
16
+ | save_execution_output | MDE_SAVE_EXECUTION_OUTPUT | `--save-execution-output` | False | Save standard output of the executed script |
17
+ | saved_script_filename_prefix | MDE_SAVED_SCRIPT_FILENAME_PREFIX | | `mde` | Name prefix for saved scripts |
18
+ | saved_script_folder | MDE_SAVED_SCRIPT_FOLDER | `--saved-script-folder` | `logs` | Saved script folder |
19
+ | saved_script_glob | MDE_SAVED_SCRIPT_GLOB | | `mde_*.sh` | Glob matching saved scripts |
20
+ | saved_stdout_folder | MDE_SAVED_STDOUT_FOLDER | `--saved-stdout-folder` | `logs` | Saved stdout folder |
28
21
 
29
- - cmd to list last n
30
- - cmd to repeat last
22
+ ### Changed
31
23
 
32
- ## [Unreleased]
24
+ - Fix saving of executed script.
25
+ - Sort configuration keys output by `-0` (Show configuration.)
33
26
 
34
- ## [0.2.3] - 2022-03
27
+ ## [0.2.3] - 2022-03-29
35
28
 
36
29
  ### Added
37
30
 
@@ -45,9 +38,7 @@
45
38
  ### Changed
46
39
 
47
40
  - Naming saved script files: The file name contains the time stamp, document name, and block name.
48
-
49
41
  - Renamed folder with fixtures.
50
-
51
42
  - Command options:
52
43
 
53
44
  | YAML Name | Environment Variable | Option Name | Default | Purpose |
@@ -70,8 +61,8 @@
70
61
  | block_name_excluded_match | MDE_BLOCK_NAME_EXCLUDED_MATCH | `^\(.+\)$` |
71
62
  | block_name_match | MDE_BLOCK_NAME_MATCH | `:(?<title>\S+)( \|$)` |
72
63
  | block_required_scan | MDE_BLOCK_REQUIRED_SCAN | `\+\S+` |
73
- | fenced_start_and_end_match | MDE_FENCED_START_AND_END_MATCH | `^\`{3,}` |
74
- | fenced_start_ex_match | MDE_FENCED_START_EX_MATCH | `^\`{3,}(?<shell>[^\`\s]*) *(?<name>.*)$` |
64
+ | fenced_start_and_end_match | MDE_FENCED_START_AND_END_MATCH | ``^`{3,}`` |
65
+ | fenced_start_ex_match | MDE_FENCED_START_EX_MATCH | ``^`{3,}(?<shell>[^`\s]*) *(?<name>.*)$`` |
75
66
  | heading1_match | MDE_HEADING1_MATCH | `^# *(?<name>[^#]*?) *$` |
76
67
  | heading2_match | MDE_HEADING2_MATCH | `^## *(?<name>[^#]*?) *$` |
77
68
  | heading3_match | MDE_HEADING3_MATCH | `^### *(?<name>.+?) *$` |
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- markdown_exec (0.2.3)
4
+ markdown_exec (0.2.4)
5
5
  open3 (~> 0.1.1)
6
6
  optparse (~> 0.1.1)
7
7
  tty-prompt (~> 0.23.1)
@@ -4,5 +4,5 @@ module MarkdownExec
4
4
  APP_NAME = 'MDE'
5
5
  APP_DESC = 'Markdown block executor'
6
6
  GEM_NAME = 'markdown_exec'
7
- VERSION = '0.2.3'
7
+ VERSION = '0.2.4'
8
8
  end
data/lib/markdown_exec.rb CHANGED
@@ -98,15 +98,24 @@ module MarkdownExec
98
98
  # commands
99
99
  list_blocks: false, # command
100
100
  list_docs: false, # command
101
+ list_recent_scripts: false, # command
102
+ run_last_script: false, # command
103
+ select_recent_script: false, # command
101
104
 
102
105
  # command options
103
106
  filename: env_str('MDE_FILENAME', default: nil), # option Filename to open
107
+ list_count: 16,
108
+ logged_stdout_filename_prefix: 'mde',
104
109
  output_execution_summary: env_bool('MDE_OUTPUT_EXECUTION_SUMMARY', default: false), # option
105
110
  output_script: env_bool('MDE_OUTPUT_SCRIPT', default: false), # option
106
111
  output_stdout: env_bool('MDE_OUTPUT_STDOUT', default: true), # option
107
112
  path: env_str('MDE_PATH', default: nil), # option Folder to search for files
108
113
  save_executed_script: env_bool('MDE_SAVE_EXECUTED_SCRIPT', default: false), # option
114
+ save_execution_output: env_bool('MDE_SAVE_EXECUTION_OUTPUT', default: false), # option
115
+ saved_script_filename_prefix: 'mde',
109
116
  saved_script_folder: env_str('MDE_SAVED_SCRIPT_FOLDER', default: 'logs'), # option
117
+ saved_script_glob: 'mde_*.sh',
118
+ saved_stdout_folder: env_str('MDE_SAVED_STDOUT_FOLDER', default: 'logs'), # option
110
119
  user_must_approve: env_bool('MDE_USER_MUST_APPROVE', default: true), # option Pause for user to approve script
111
120
 
112
121
  # configuration options
@@ -129,10 +138,11 @@ module MarkdownExec
129
138
  {
130
139
  bash: true, # bash block parsing in get_block_summary()
131
140
  exclude_expect_blocks: true,
132
- exclude_matching_block_names: true, # exclude hidden blocks
141
+ hide_blocks_by_name: true,
133
142
  output_saved_script_filename: false,
134
- prompt_select_block: 'Choose a block:', # in select_and_approve_block()
135
- prompt_select_md: 'Choose a file:', # in select_md_file()
143
+ prompt_approve_block: 'Process?',
144
+ prompt_select_block: 'Choose a block:',
145
+ prompt_select_md: 'Choose a file:',
136
146
  saved_script_filename: nil, # calculated
137
147
  struct: true # allow get_block_summary()
138
148
  }
@@ -149,7 +159,7 @@ module MarkdownExec
149
159
  display_command(opts, required_blocks) if opts[:output_script] || opts[:user_must_approve]
150
160
 
151
161
  allow = true
152
- allow = @prompt.yes? 'Process?' if opts[:user_must_approve]
162
+ allow = @prompt.yes? opts[:prompt_approve_block] if opts[:user_must_approve]
153
163
  opts[:ir_approve] = allow
154
164
  selected = get_block_by_name blocks_in_file, opts[:block_name]
155
165
 
@@ -171,6 +181,7 @@ module MarkdownExec
171
181
  end
172
182
 
173
183
  def command_execute(opts, cmd2)
184
+ @execute_files = Hash.new([])
174
185
  @execute_options = opts
175
186
  @execute_started_at = Time.now.utc
176
187
  Open3.popen3(cmd2) do |stdin, stdout, stderr|
@@ -186,7 +197,6 @@ module MarkdownExec
186
197
  # readable = ready[0]
187
198
  # # writable = ready[1]
188
199
  # # exceptions = ready[2]
189
- @execute_files = Hash.new([])
190
200
  ready.each.with_index do |readable, ind|
191
201
  readable.each do |f|
192
202
  block = f.read_nonblock(BLOCK_SIZE)
@@ -203,9 +213,11 @@ module MarkdownExec
203
213
  @execute_completed_at = Time.now.utc
204
214
  end
205
215
  rescue Errno::ENOENT => e
216
+ # error triggered by missing command in script
206
217
  @execute_aborted_at = Time.now.utc
207
218
  @execute_error_message = e.message
208
219
  @execute_error = e
220
+ @execute_files[1] = e.message
209
221
  fout "Error ENOENT: #{e.inspect}"
210
222
  end
211
223
 
@@ -222,37 +234,50 @@ module MarkdownExec
222
234
  required_blocks.each { |cb| fout cb }
223
235
  end
224
236
 
225
- def exec_block(options, block_name = '')
237
+ def exec_block(options, _block_name = '')
226
238
  options = default_options.merge options
227
239
  update_options options, over: false
228
240
 
229
241
  # document and block reports
230
242
  #
231
243
  files = list_files_per_options(options)
244
+ if @options[:list_blocks]
245
+ fout_list (files.map do |file|
246
+ make_block_labels(filename: file, struct: true)
247
+ end).flatten(1)
248
+ return
249
+ end
250
+
232
251
  if @options[:list_docs]
233
252
  fout_list files
234
253
  return
235
254
  end
236
255
 
237
- if @options[:list_blocks]
238
- fout_list (files.map do |file|
239
- make_block_labels(filename: file, struct: true)
240
- end).flatten(1)
256
+ if @options[:list_recent_scripts]
257
+ fout_list list_recent_scripts
258
+ return
259
+ end
260
+
261
+ if @options[:run_last_script]
262
+ run_last_script
263
+ return
264
+ end
265
+
266
+ if @options[:select_recent_script]
267
+ select_recent_script
241
268
  return
242
269
  end
243
270
 
244
271
  # process
245
272
  #
273
+ @options[:filename] = select_md_file(files)
246
274
  select_and_approve_block(
247
275
  bash: true,
248
- block_name: block_name,
249
- filename: select_md_file(files),
250
276
  struct: true
251
277
  )
252
-
253
278
  fout "saved_filespec: #{@execute_script_filespec}" if @options[:output_saved_script_filename]
254
-
255
- output_execution_summary if @options[:output_execution_summary]
279
+ save_execution_output
280
+ output_execution_summary
256
281
  end
257
282
 
258
283
  # standard output; not for debug
@@ -394,7 +419,7 @@ module MarkdownExec
394
419
  opts = optsmerge call_options, options_block
395
420
  block_name_excluded_match = Regexp.new opts[:block_name_excluded_match]
396
421
  list_blocks_in_file(opts).map do |block|
397
- next if opts[:exclude_matching_block_names] && block[:name].match(block_name_excluded_match)
422
+ next if opts[:hide_blocks_by_name] && block[:name].match(block_name_excluded_match)
398
423
 
399
424
  block
400
425
  end.compact.tap_inspect
@@ -413,6 +438,11 @@ module MarkdownExec
413
438
  .tap_inspect
414
439
  end
415
440
 
441
+ def list_recent_scripts
442
+ Dir.glob(File.join(@options[:saved_script_folder],
443
+ @options[:saved_script_glob])).sort[0..(options[:list_count] - 1)].reverse.tap_inspect
444
+ end
445
+
416
446
  def make_block_label(block, call_options = {})
417
447
  opts = options.merge(call_options)
418
448
  if opts[:mdheadings]
@@ -426,7 +456,7 @@ module MarkdownExec
426
456
  def make_block_labels(call_options = {})
427
457
  opts = options.merge(call_options)
428
458
  list_blocks_in_file(opts).map do |block|
429
- # next if opts[:exclude_matching_block_names] && block[:name].match(%r{^:\(.+\)$})
459
+ # next if opts[:hide_blocks_by_name] && block[:name].match(%r{^:\(.+\)$})
430
460
 
431
461
  make_block_label block, opts
432
462
  end.compact.tap_inspect
@@ -434,7 +464,7 @@ module MarkdownExec
434
464
 
435
465
  def option_exclude_blocks(opts, blocks)
436
466
  block_name_excluded_match = Regexp.new opts[:block_name_excluded_match]
437
- if opts[:exclude_matching_block_names]
467
+ if opts[:hide_blocks_by_name]
438
468
  blocks.reject { |block| block[:name].match(block_name_excluded_match) }
439
469
  else
440
470
  blocks
@@ -451,6 +481,8 @@ module MarkdownExec
451
481
  end
452
482
 
453
483
  def output_execution_summary
484
+ return unless @options[:output_execution_summary]
485
+
454
486
  fout_section 'summary', {
455
487
  execute_aborted_at: @execute_aborted_at,
456
488
  execute_completed_at: @execute_completed_at,
@@ -528,6 +560,8 @@ module MarkdownExec
528
560
  :list_blocks, proc_true],
529
561
  ['list-docs', nil, nil, nil, 'List docs in current folder',
530
562
  :list_docs, proc_true],
563
+ ['list-recent-scripts', nil, nil, nil, 'List recent saved scripts',
564
+ :list_recent_scripts, proc_true],
531
565
  ['output-execution-summary', nil, 'MDE_OUTPUT_EXECUTION_SUMMARY', 'BOOL', 'Display summary for execution',
532
566
  :output_execution_summary, proc_to_i],
533
567
  ['output-script', nil, 'MDE_OUTPUT_SCRIPT', 'BOOL', 'Display script',
@@ -536,10 +570,18 @@ module MarkdownExec
536
570
  :output_stdout, proc_to_i],
537
571
  ['path', 'p', 'MDE_PATH', 'PATH', 'Path to documents',
538
572
  :path, proc_self],
573
+ ['run-last-script', nil, nil, nil, 'Run most recently saved script',
574
+ :run_last_script, proc_true],
575
+ ['select-recent-script', nil, nil, nil, 'Select and execute a recently saved script',
576
+ :select_recent_script, proc_true],
577
+ ['save-execution-output', nil, 'MDE_SAVE_EXECUTION_OUTPUT', 'BOOL', 'Save execution output',
578
+ :save_execution_output, proc_to_i],
539
579
  ['save-executed-script', nil, 'MDE_SAVE_EXECUTED_SCRIPT', 'BOOL', 'Save executed script',
540
580
  :save_executed_script, proc_to_i],
541
581
  ['saved-script-folder', nil, 'MDE_SAVED_SCRIPT_FOLDER', 'SPEC', 'Saved script folder',
542
582
  :saved_script_folder, proc_self],
583
+ ['saved-stdout-folder', nil, 'MDE_SAVED_STDOUT_FOLDER', 'SPEC', 'Saved stdout folder',
584
+ :saved_stdout_folder, proc_self],
543
585
  ['user-must-approve', nil, 'MDE_USER_MUST_APPROVE', 'BOOL', 'Pause to approve execution',
544
586
  :user_must_approve, proc_to_i]
545
587
  ]
@@ -547,7 +589,7 @@ module MarkdownExec
547
589
  # rubocop:disable Style/Semicolon
548
590
  summary_tail = [
549
591
  [nil, '0', nil, nil, 'Show configuration',
550
- nil, ->(_) { options_finalize.call options; fout options.to_yaml }],
592
+ nil, ->(_) { options_finalize.call options; fout sorted_keys(options).to_yaml }],
551
593
  ['help', 'h', nil, nil, 'App help',
552
594
  nil, ->(_) { fout option_parser.help; exit }],
553
595
  ['version', 'v', nil, nil, 'App version',
@@ -559,7 +601,9 @@ module MarkdownExec
559
601
 
560
602
  (summary_head + summary_body + summary_tail)
561
603
  .map do |long_name, short_name, env_var, arg_name, description, opt_name, proc1| # rubocop:disable Metrics/ParameterLists
562
- opts.on(*[long_name.present? ? "--#{long_name}#{arg_name.present? ? (' ' + arg_name) : ''}" : nil,
604
+ opts.on(*[if long_name.present?
605
+ "--#{long_name}#{arg_name.present? ? " #{arg_name}" : ''}"
606
+ end,
563
607
  short_name.present? ? "-#{short_name}" : nil,
564
608
  [description,
565
609
  env_var.present? ? "env: #{env_var}" : nil].compact.join(' - '),
@@ -597,6 +641,34 @@ module MarkdownExec
597
641
  exec_block options, block_name
598
642
  end
599
643
 
644
+ def run_last_script
645
+ filename = Dir.glob(File.join(@options[:saved_script_folder],
646
+ @options[:saved_script_glob])).sort[0..(options[:list_count] - 1)].last
647
+ filename.tap_inspect name: filename
648
+ mf = filename.match(/#{@options[:saved_script_filename_prefix]}_(?<time>[0-9\-]+)_(?<file>.+)_(?<block>.+)\.sh/)
649
+
650
+ @options[:block_name] = mf[:block]
651
+ @options[:filename] = "#{mf[:file]}.md" ### other extensions
652
+ @options[:save_executed_script] = false
653
+ select_and_approve_block
654
+ save_execution_output
655
+ output_execution_summary
656
+ end
657
+
658
+ def save_execution_output
659
+ return unless @options[:save_execution_output]
660
+
661
+ fne = File.basename(@options[:filename], '.*')
662
+ @options[:logged_stdout_filename] =
663
+ "#{[@options[:logged_stdout_filename_prefix], Time.now.utc.strftime('%F-%H-%M-%S'), fne,
664
+ @options[:block_name]].join('_')}.out.txt"
665
+ @options[:logged_stdout_filespec] = File.join @options[:saved_stdout_folder], @options[:logged_stdout_filename]
666
+ @logged_stdout_filespec = @options[:logged_stdout_filespec]
667
+ dirname = File.dirname(@options[:logged_stdout_filespec])
668
+ Dir.mkdir dirname unless File.exist?(dirname)
669
+ File.write(@options[:logged_stdout_filespec], @execute_files&.fetch(0, ''))
670
+ end
671
+
600
672
  def select_and_approve_block(call_options = {}, &options_block)
601
673
  opts = optsmerge call_options, options_block
602
674
  blocks_in_file = list_blocks_in_file(opts.merge(struct: true))
@@ -608,9 +680,9 @@ module MarkdownExec
608
680
 
609
681
  return nil if block_labels.count.zero?
610
682
 
611
- sel = @prompt.select(pt, block_labels, per_page: opts[:select_page_height])
683
+ sel = @prompt.select pt, block_labels, per_page: opts[:select_page_height]
612
684
  label_block = blocks_in_file.select { |block| block[:label] == sel }.fetch(0, nil)
613
- opts[:block_name] = label_block[:name]
685
+ opts[:block_name] = @options[:block_name] = label_block[:name]
614
686
  end
615
687
 
616
688
  approve_block opts, blocks_in_file
@@ -622,10 +694,30 @@ module MarkdownExec
622
694
  if files.count == 1
623
695
  files[0]
624
696
  elsif files.count >= 2
625
- @prompt.select(opts[:prompt_select_md].to_s, files, per_page: opts[:select_page_height])
697
+ @prompt.select opts[:prompt_select_md].to_s, files, per_page: opts[:select_page_height]
626
698
  end
627
699
  end
628
700
 
701
+ def select_recent_script
702
+ filename = @prompt.select @options[:prompt_select_md].to_s, list_recent_scripts,
703
+ per_page: @options[:select_page_height]
704
+ mf = filename.match(/#{@options[:saved_script_filename_prefix]}_(?<time>[0-9\-]+)_(?<file>.+)_(?<block>.+)\.sh/)
705
+
706
+ @options[:block_name] = mf[:block]
707
+ @options[:filename] = "#{mf[:file]}.md" ### other extensions
708
+ select_and_approve_block(
709
+ bash: true,
710
+ save_executed_script: false,
711
+ struct: true
712
+ )
713
+ save_execution_output
714
+ output_execution_summary
715
+ end
716
+
717
+ def sorted_keys(hash1)
718
+ hash1.keys.sort.to_h { |k| [k, hash1[k]] }
719
+ end
720
+
629
721
  def summarize_block(headings, title)
630
722
  { headings: headings, name: title, title: title }
631
723
  end
@@ -640,12 +732,10 @@ module MarkdownExec
640
732
  end
641
733
 
642
734
  def write_command_file(opts, required_blocks)
643
- return unless opts[:saved_script_filename].present?
644
-
645
- fne = File.basename(opts[:filename], '.*').gsub(/[^a-z0-9]/i, '-') # scan(/[a-z0-9]/i).join
646
- bne = opts[:block_name].gsub(/[^a-z0-9]/i, '-') # scan(/[a-z0-9]/i).join
647
- opts[:saved_script_filename] = "mde_#{Time.now.utc.strftime '%F-%H-%M-%S'}_#{fne}_#{bne}.sh"
648
-
735
+ fne = File.basename(opts[:filename], '.*')
736
+ opts[:saved_script_filename] =
737
+ "#{[opts[:saved_script_filename_prefix], Time.now.utc.strftime('%F-%H-%M-%S'), fne,
738
+ opts[:block_name]].join('_')}.sh"
649
739
  @options[:saved_filespec] = File.join opts[:saved_script_folder], opts[:saved_script_filename]
650
740
  @execute_script_filespec = @options[:saved_filespec]
651
741
  dirname = File.dirname(@options[:saved_filespec])
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: markdown_exec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fareed Stevenson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-30 00:00:00.000000000 Z
11
+ date: 2022-04-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: open3