markdown_exec 0.2.3 → 0.2.4

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 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