rundoc 4.1.4 → 6.0.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/.github/workflows/ci.yml +3 -1
- data/.standard.yml +1 -1
- data/CHANGELOG.md +12 -0
- data/README.md +98 -10
- data/lib/rundoc/cli.rb +18 -2
- data/lib/rundoc/code_command/background/log/clear.rb +12 -2
- data/lib/rundoc/code_command/background/log/read.rb +12 -2
- data/lib/rundoc/code_command/background/process_spawn.rb +3 -1
- data/lib/rundoc/code_command/background/start.rb +25 -6
- data/lib/rundoc/code_command/background/stdin_write.rb +21 -8
- data/lib/rundoc/code_command/background/stop.rb +12 -2
- data/lib/rundoc/code_command/background/wait.rb +15 -3
- data/lib/rundoc/code_command/background.rb +2 -0
- data/lib/rundoc/code_command/bash/cd.rb +12 -18
- data/lib/rundoc/code_command/bash.rb +43 -19
- data/lib/rundoc/code_command/comment.rb +33 -0
- data/lib/rundoc/code_command/deferred.rb +66 -0
- data/lib/rundoc/code_command/empty_binding.rb +18 -0
- data/lib/rundoc/code_command/file_command/append.rb +29 -8
- data/lib/rundoc/code_command/file_command/remove.rb +27 -5
- data/lib/rundoc/code_command/no_such_command.rb +8 -3
- data/lib/rundoc/code_command/pipe.rb +36 -16
- data/lib/rundoc/code_command/pre/erb.rb +28 -18
- data/lib/rundoc/code_command/print/erb.rb +27 -16
- data/lib/rundoc/code_command/print/text.rb +27 -8
- data/lib/rundoc/code_command/raw.rb +17 -5
- data/lib/rundoc/code_command/rundoc/ensure_later.rb +59 -0
- data/lib/rundoc/code_command/rundoc/require.rb +25 -17
- data/lib/rundoc/code_command/rundoc_command.rb +26 -9
- data/lib/rundoc/code_command/website/driver.rb +2 -0
- data/lib/rundoc/code_command/website/navigate.rb +18 -12
- data/lib/rundoc/code_command/website/screenshot.rb +17 -11
- data/lib/rundoc/code_command/website/visit.rb +23 -12
- data/lib/rundoc/code_command/website.rb +2 -0
- data/lib/rundoc/code_command/write.rb +37 -9
- data/lib/rundoc/code_command.rb +6 -48
- data/lib/rundoc/context/after_build.rb +2 -0
- data/lib/rundoc/context/execution.rb +2 -0
- data/lib/rundoc/document.rb +6 -2
- data/lib/rundoc/fenced_code_block.rb +10 -7
- data/lib/rundoc/peg_parser.rb +25 -9
- data/lib/rundoc/version.rb +3 -1
- data/lib/rundoc.rb +89 -17
- data/rundoc.gemspec +3 -0
- data/test/integration/ensure_later_test.rb +335 -0
- data/test/integration/print_test.rb +51 -0
- data/test/rundoc/code_commands/append_file_test.rb +35 -10
- data/test/rundoc/code_commands/background_test.rb +24 -22
- data/test/rundoc/code_commands/bash_test.rb +10 -5
- data/test/rundoc/code_commands/comment_test.rb +116 -0
- data/test/rundoc/code_commands/pipe_test.rb +2 -2
- data/test/rundoc/code_commands/print_test.rb +13 -25
- data/test/rundoc/code_commands/remove_contents_test.rb +8 -3
- data/test/rundoc/code_section_test.rb +28 -21
- data/test/rundoc/peg_parser_test.rb +42 -1
- data/test/test_helper.rb +4 -2
- metadata +23 -6
- data/lib/rundoc/code_command/rundoc/depend_on.rb +0 -13
- data/test/fixtures/depend_on/dependency/rundoc.md +0 -5
- data/test/fixtures/depend_on/main/rundoc.md +0 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 498d5109daa7abb733fc5c27cf583bb1c84cc7b92bbccaaf9e005a51a6ec0555
|
|
4
|
+
data.tar.gz: fc72016241033a945486b5fa893b3f2cad0c8b3c7a2c44eab3f964adb7308f9e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5af654672de3e6051ec46377052c55b55207ce13eb29cf977d1cf793291e953d28e842fd79b0f0972f8eb83a98c6671c1834a5ac75f20da795eb686a99a02c52
|
|
7
|
+
data.tar.gz: b2acdf08759aa0c6f73410a00a4ad387da198f1f4497228c69d27dd799799e12107cc421c8f3fd5242f9517dbfd2565e71b56e2b3a6ffd77ffd879906c902d65
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -11,9 +11,10 @@ jobs:
|
|
|
11
11
|
fail-fast: false
|
|
12
12
|
matrix:
|
|
13
13
|
ruby:
|
|
14
|
-
- 3.1
|
|
15
14
|
- 3.2
|
|
16
15
|
- 3.3
|
|
16
|
+
- 3.4
|
|
17
|
+
- "4.0"
|
|
17
18
|
- head
|
|
18
19
|
steps:
|
|
19
20
|
- name: Checkout code
|
|
@@ -34,6 +35,7 @@ jobs:
|
|
|
34
35
|
matrix:
|
|
35
36
|
ruby:
|
|
36
37
|
- 3.3
|
|
38
|
+
- "4.0"
|
|
37
39
|
- head
|
|
38
40
|
steps:
|
|
39
41
|
- name: Checkout code
|
data/.standard.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
## HEAD
|
|
2
2
|
|
|
3
|
+
## 6.0.0
|
|
4
|
+
|
|
5
|
+
- Added: `rundoc.ensure_later(dir: :cwd)` command to register cleanup blocks that run on every build (success and failure). Useful for guaranteed resource teardown (e.g., destroying Heroku apps). Multiple blocks execute in order; failures in one block do not stop the rest.
|
|
6
|
+
- Changed: The ruby context in `rundoc` and `rundoc.configure` commands is now the same binding as the default ERB evaluation. This means that methods can be defined in one and used in both.
|
|
7
|
+
|
|
8
|
+
## 5.0.0
|
|
9
|
+
|
|
10
|
+
- Added comment syntax. Use an octothorpe (`#`) after the visibility markers to comment out any commands and make them a no-op.
|
|
11
|
+
- Changed: Minimum Ruby version is now 3.2 (Ruby 3.1 reached EOL in March 2025).
|
|
12
|
+
- Changed: All code commands now use an Args + Runner class pattern. `register_code_command` now requires keyword arguments: `keyword:`, `args_klass:`, and `runner_klass:`.
|
|
13
|
+
- Fix: `seattle_method` parser rule no longer matches across newlines. Previously, a command with no same-line arguments (e.g. `:::>> rundoc`) would consume the next line as its argument, losing the newline between content lines. (https://github.com/zombocom/rundoc/pull/118)
|
|
14
|
+
|
|
3
15
|
## 4.1.4
|
|
4
16
|
|
|
5
17
|
- Fix: Net::ReadTimeout errors on `website.visit` are now retried by default (https://github.com/zombocom/rundoc/pull/103)
|
data/README.md
CHANGED
|
@@ -98,6 +98,8 @@ This will generate a project folder with your project in it, and a markdown `REA
|
|
|
98
98
|
- [website.screenshot](#screenshots)
|
|
99
99
|
- Configure RunDOC
|
|
100
100
|
- [rundoc.configure](#configure)
|
|
101
|
+
- [rundoc.ensure_later](#ensure_later)
|
|
102
|
+
- [rundoc](#configure) an alias for `rundoc.configure`
|
|
101
103
|
- Import and compose documents
|
|
102
104
|
- [rundoc.require](#compose-multiple-rundoc-documents)
|
|
103
105
|
|
|
@@ -616,7 +618,7 @@ If you need to specify project specific environment variables create a file call
|
|
|
616
618
|
|
|
617
619
|
## Configure
|
|
618
620
|
|
|
619
|
-
You can configure your docs in your docs use the `RunDOC` command
|
|
621
|
+
You can configure your docs in your docs use the `RunDOC` command via `rundoc.configure` (or alias `rundoc`):
|
|
620
622
|
|
|
621
623
|
```
|
|
622
624
|
:::-- rundoc.configure
|
|
@@ -624,6 +626,30 @@ You can configure your docs in your docs use the `RunDOC` command
|
|
|
624
626
|
|
|
625
627
|
Note: Make sure you run this as a hidden command (with `-`).
|
|
626
628
|
|
|
629
|
+
This will give you a Ruby codeblock that executes and gives you access to `Rundoc.configure do |config|` to configure things about your build (such as modifying your markdown document after successful builds).
|
|
630
|
+
|
|
631
|
+
**Define and Re-use logic**
|
|
632
|
+
|
|
633
|
+
Since it's **just ruby** :tm: you can also use it to define shared logic that can be re-used in ERB templates. For example:
|
|
634
|
+
|
|
635
|
+
```
|
|
636
|
+
:::-- rundoc
|
|
637
|
+
def run!(command, quiet: false, error_on_fail: true)
|
|
638
|
+
puts "Running `#{command}`" unless quiet
|
|
639
|
+
output = `#{command}`
|
|
640
|
+
puts "Command `#{command}` output:\n#{output}" unless quiet
|
|
641
|
+
if error_on_fail && !$?.success?
|
|
642
|
+
raise "Error running #{command}. Output:\n#{output}"
|
|
643
|
+
end
|
|
644
|
+
output
|
|
645
|
+
end
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
```
|
|
649
|
+
:::-> print.erb
|
|
650
|
+
Hello <%= run!("heroku whoami") %>!
|
|
651
|
+
```
|
|
652
|
+
|
|
627
653
|
**After Build**
|
|
628
654
|
|
|
629
655
|
This will eval any code you put under that line (in Ruby) when the build was successful but before the contents are finalized on disk. If you want to run some code after you're done building your docs you could use `Rundoc.configure` block and call the `after_build` method like this:
|
|
@@ -658,38 +684,100 @@ Sometimes sensitive info like usernames, email addresses, or passwords may be in
|
|
|
658
684
|
|
|
659
685
|
This command `filter_sensitive` can be called multiple times with different values. Since the config is in Ruby you could iterate over an array of sensitive data
|
|
660
686
|
|
|
687
|
+
## Ensure Later
|
|
688
|
+
|
|
689
|
+
Run a script on EVERY build (success and failure). Used to guarantee resources are cleaned up.
|
|
690
|
+
|
|
691
|
+
- Arguments
|
|
692
|
+
- `dir:` The directory where the script will be run. Must be one of these values:
|
|
693
|
+
- `:cwd` The directory where the command is first invoked. If this directory does not exist when the `rundoc.ensure_later` is invoked, it will raise an error.
|
|
694
|
+
- `:rundoc_root` The tmp directory where the script is being executed. Useful if the directory where the `rundoc.ensure_later` is defined, is deleted by the rundoc script.
|
|
695
|
+
|
|
696
|
+
For example:
|
|
697
|
+
|
|
698
|
+
```
|
|
699
|
+
:::>> $ heroku create
|
|
700
|
+
:::-- rundoc
|
|
701
|
+
@app_name = run!("heroku info --json | jq -r '.app.name'").strip
|
|
702
|
+
|
|
703
|
+
def app_name
|
|
704
|
+
@app_name
|
|
705
|
+
end
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
```ruby
|
|
709
|
+
:::-- rundoc.ensure_later(dir: :cwd)
|
|
710
|
+
if run!("heroku apps").include?(app_name)
|
|
711
|
+
puts "Cleaning up web app #{app_name}"
|
|
712
|
+
run!("heroku apps:destroy #{app_name} --confirm #{app_name}")
|
|
713
|
+
else
|
|
714
|
+
puts "App `#{app_name}` already cleaned, nothing to do"
|
|
715
|
+
end
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
The output of this will not be included in the document. Multiple ensure blocks can be defined and will execute in the order of their definition. Since they'll be executed EVERY time, logic must handle both success and failure cases. This execution occurs before the temp directory is removed, and before any background task shutdown ensure blocks are triggered.
|
|
719
|
+
|
|
720
|
+
If a build is successful, but an `ensure_later` block fails, the build will be considered a failure. A failure in one block will not stop the rest from executing.
|
|
721
|
+
|
|
661
722
|
## Writing a new command
|
|
662
723
|
|
|
724
|
+
> Note: This is an advanced topic and this interface is unstable.
|
|
725
|
+
|
|
663
726
|
Rundoc does not have a stable internal command interface. You can define your own commands, but unless it is committed in this repo, it may break on a minor version change.
|
|
664
727
|
|
|
665
728
|
To add a new command it needs to be parsed and called. Examples of commands being implemented are seen in `lib/rundoc/code_command`.
|
|
666
729
|
|
|
667
|
-
|
|
730
|
+
Each command is split into two classes: an **Args** class that handles argument parsing/validation and a **Runner** class that handles execution. Both must be registered:
|
|
668
731
|
|
|
732
|
+
```ruby
|
|
733
|
+
Rundoc.register_code_command(
|
|
734
|
+
keyword: :lol,
|
|
735
|
+
args_klass: Rundoc::CodeCommand::LolArgs,
|
|
736
|
+
runner_klass: Rundoc::CodeCommand::LolRunner
|
|
737
|
+
)
|
|
669
738
|
```
|
|
670
|
-
Rundoc.register_code_command(:lol, Rundoc::CodeCommand::Lol)
|
|
671
|
-
```
|
|
672
739
|
|
|
673
|
-
|
|
740
|
+
The Args class is a plain Ruby class. Its initialize method receives input from the document and exposes parsed values via `attr_reader`:
|
|
741
|
+
|
|
742
|
+
```ruby
|
|
743
|
+
class Rundoc::CodeCommand::LolArgs
|
|
744
|
+
attr_reader :message
|
|
674
745
|
|
|
746
|
+
def initialize(message)
|
|
747
|
+
@message = message
|
|
748
|
+
end
|
|
749
|
+
end
|
|
675
750
|
```
|
|
676
|
-
|
|
677
|
-
|
|
751
|
+
|
|
752
|
+
The Runner class is namespaced under `Rundoc::CodeCommand` and receives the args instance via `user_args:`:
|
|
753
|
+
|
|
754
|
+
```ruby
|
|
755
|
+
class Rundoc::CodeCommand::LolRunner
|
|
756
|
+
def initialize(user_args:, **)
|
|
757
|
+
@message = user_args.message
|
|
758
|
+
end
|
|
759
|
+
|
|
760
|
+
def to_md(env = {})
|
|
761
|
+
""
|
|
762
|
+
end
|
|
763
|
+
|
|
764
|
+
def call(env = {})
|
|
765
|
+
@message
|
|
678
766
|
end
|
|
679
767
|
end
|
|
680
768
|
```
|
|
681
769
|
|
|
682
|
-
The
|
|
770
|
+
The command is rendered (`:::>-`) by the output of the `def call` method. The contents produced by the command (`:::->`) are rendered by the `def to_md` method.
|
|
683
771
|
|
|
684
772
|
The syntax for commands is ruby-ish but it is a custom grammar implemented in `lib/peg_parser.rb` for more info on manipulating the grammar see this tutorial on how I added keword-like/hash-like syntax https://github.com/schneems/implement_ruby_hash_syntax_with_parslet_example.
|
|
685
773
|
|
|
686
|
-
|
|
774
|
+
Args class initialize methods natively support:
|
|
687
775
|
|
|
688
776
|
- Barewords as a single string input
|
|
689
777
|
- Keyword arguments
|
|
690
778
|
- A combination of the two
|
|
691
779
|
|
|
692
|
-
Anything that is passed to the command via "stdin" is available via a method `self.contents`. The interplay between the input and `self.contents` is not strongly defined.
|
|
780
|
+
Anything that is passed to the command via "stdin" is available on the Runner via a method `self.contents`. The interplay between the input and `self.contents` is not strongly defined.
|
|
693
781
|
|
|
694
782
|
## Copyright
|
|
695
783
|
|
data/lib/rundoc/cli.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Rundoc
|
|
2
4
|
class CLI
|
|
3
5
|
module DEFAULTS
|
|
@@ -132,6 +134,9 @@ module Rundoc
|
|
|
132
134
|
end
|
|
133
135
|
|
|
134
136
|
def call
|
|
137
|
+
build_success = false
|
|
138
|
+
ensure_later_errors = []
|
|
139
|
+
|
|
135
140
|
io.puts "## Running your docs"
|
|
136
141
|
load_dotenv
|
|
137
142
|
check_directories_empty!
|
|
@@ -159,10 +164,15 @@ module Rundoc
|
|
|
159
164
|
Dir.chdir(execution_context.output_dir) do
|
|
160
165
|
parser = Rundoc::Document.new(
|
|
161
166
|
source_contents,
|
|
162
|
-
context: execution_context
|
|
167
|
+
context: execution_context,
|
|
168
|
+
io: io
|
|
163
169
|
)
|
|
164
170
|
output = begin
|
|
165
|
-
|
|
171
|
+
begin
|
|
172
|
+
parser.to_md
|
|
173
|
+
ensure
|
|
174
|
+
ensure_later_errors = Rundoc.run_ensure_later(io: io)
|
|
175
|
+
end
|
|
166
176
|
rescue StandardError, SignalException => e
|
|
167
177
|
io.puts "Received exception: #{e.inspect}, cleaning up before re-raise"
|
|
168
178
|
on_fail
|
|
@@ -171,6 +181,8 @@ module Rundoc
|
|
|
171
181
|
|
|
172
182
|
on_success(output)
|
|
173
183
|
end
|
|
184
|
+
|
|
185
|
+
build_success = true
|
|
174
186
|
ensure
|
|
175
187
|
# Stop any hanging background tasks
|
|
176
188
|
Rundoc::CodeCommand::Background::ProcessSpawn.tasks.each do |name, task|
|
|
@@ -186,6 +198,10 @@ module Rundoc
|
|
|
186
198
|
description: "tmp working directory"
|
|
187
199
|
)
|
|
188
200
|
end
|
|
201
|
+
|
|
202
|
+
if ensure_later_errors.any? && build_success
|
|
203
|
+
raise ensure_later_errors.first
|
|
204
|
+
end
|
|
189
205
|
end
|
|
190
206
|
|
|
191
207
|
private def clean_dir(dir:, description:)
|
|
@@ -1,7 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
class Rundoc::CodeCommand::Background::Log
|
|
2
|
-
class
|
|
4
|
+
class ClearArgs
|
|
5
|
+
attr_reader :name
|
|
6
|
+
|
|
3
7
|
def initialize(name:)
|
|
4
8
|
@name = name
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class ClearRunner
|
|
13
|
+
def initialize(user_args:, render_command:, render_result:, io: nil, contents: nil)
|
|
14
|
+
@name = user_args.name
|
|
5
15
|
@background = nil
|
|
6
16
|
end
|
|
7
17
|
|
|
@@ -19,4 +29,4 @@ class Rundoc::CodeCommand::Background::Log
|
|
|
19
29
|
end
|
|
20
30
|
end
|
|
21
31
|
end
|
|
22
|
-
Rundoc.register_code_command(:"background.log.clear", Rundoc::CodeCommand::Background::Log::
|
|
32
|
+
Rundoc.register_code_command(keyword: :"background.log.clear", args_klass: Rundoc::CodeCommand::Background::Log::ClearArgs, runner_klass: Rundoc::CodeCommand::Background::Log::ClearRunner)
|
|
@@ -1,7 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
class Rundoc::CodeCommand::Background::Log
|
|
2
|
-
class
|
|
4
|
+
class ReadArgs
|
|
5
|
+
attr_reader :name
|
|
6
|
+
|
|
3
7
|
def initialize(name:)
|
|
4
8
|
@name = name
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class ReadRunner
|
|
13
|
+
def initialize(user_args:, render_command:, render_result:, io: nil, contents: nil)
|
|
14
|
+
@name = user_args.name
|
|
5
15
|
@background = nil
|
|
6
16
|
end
|
|
7
17
|
|
|
@@ -18,4 +28,4 @@ class Rundoc::CodeCommand::Background::Log
|
|
|
18
28
|
end
|
|
19
29
|
end
|
|
20
30
|
end
|
|
21
|
-
Rundoc.register_code_command(:"background.log.read", Rundoc::CodeCommand::Background::Log::
|
|
31
|
+
Rundoc.register_code_command(keyword: :"background.log.read", args_klass: Rundoc::CodeCommand::Background::Log::ReadArgs, runner_klass: Rundoc::CodeCommand::Background::Log::ReadRunner)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "shellwords"
|
|
2
4
|
require "timeout"
|
|
3
5
|
require "fileutils"
|
|
@@ -126,7 +128,7 @@ class Rundoc::CodeCommand::Background
|
|
|
126
128
|
Process.kill("TERM", -Process.getpgid(@pid))
|
|
127
129
|
Process.wait(@pid)
|
|
128
130
|
rescue Errno::ESRCH => e
|
|
129
|
-
puts "Error stopping process (command: #{command}): #{e}"
|
|
131
|
+
print_io&.puts "Error stopping process (command: #{command}): #{e}"
|
|
130
132
|
ensure
|
|
131
133
|
print_io&.puts "Log contents for `#{command}`:\n#{@log.read}"
|
|
132
134
|
end
|
|
@@ -1,18 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "tempfile"
|
|
2
4
|
|
|
3
5
|
class Rundoc::CodeCommand::Background
|
|
4
|
-
class
|
|
6
|
+
class StartArgs
|
|
7
|
+
attr_reader :command, :name, :wait, :timeout, :log, :out, :allow_fail
|
|
8
|
+
|
|
5
9
|
def initialize(command, name:, wait: nil, timeout: 5, log: Tempfile.new("log"), out: "2>&1", allow_fail: false)
|
|
6
|
-
@timeout = timeout
|
|
7
10
|
@command = command
|
|
8
11
|
@name = name
|
|
9
12
|
@wait = wait
|
|
10
|
-
@
|
|
13
|
+
@timeout = timeout
|
|
11
14
|
@log = log
|
|
12
|
-
@
|
|
15
|
+
@out = out
|
|
16
|
+
@allow_fail = allow_fail
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class StartRunner
|
|
21
|
+
attr_reader :io
|
|
22
|
+
|
|
23
|
+
def initialize(user_args:, render_command:, render_result:, io:, contents: nil)
|
|
24
|
+
@timeout = user_args.timeout
|
|
25
|
+
@command = user_args.command
|
|
26
|
+
@name = user_args.name
|
|
27
|
+
@wait = user_args.wait
|
|
28
|
+
@allow_fail = user_args.allow_fail
|
|
29
|
+
@log = user_args.log
|
|
30
|
+
@redirect = user_args.out
|
|
13
31
|
FileUtils.touch(@log)
|
|
14
32
|
|
|
15
33
|
@background = nil
|
|
34
|
+
@io = io
|
|
16
35
|
end
|
|
17
36
|
|
|
18
37
|
def background
|
|
@@ -22,7 +41,7 @@ class Rundoc::CodeCommand::Background
|
|
|
22
41
|
log: @log,
|
|
23
42
|
out: @redirect
|
|
24
43
|
).tap do |spawn|
|
|
25
|
-
puts "Spawning commmand: `#{spawn.command}`"
|
|
44
|
+
io.puts "Spawning commmand: `#{spawn.command}`"
|
|
26
45
|
ProcessSpawn.add(@name, spawn)
|
|
27
46
|
end
|
|
28
47
|
end
|
|
@@ -44,4 +63,4 @@ class Rundoc::CodeCommand::Background
|
|
|
44
63
|
end
|
|
45
64
|
end
|
|
46
65
|
|
|
47
|
-
Rundoc.register_code_command(:"background.start", Rundoc::CodeCommand::Background::
|
|
66
|
+
Rundoc.register_code_command(keyword: :"background.start", args_klass: Rundoc::CodeCommand::Background::StartArgs, runner_klass: Rundoc::CodeCommand::Background::StartRunner)
|
|
@@ -1,14 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
class Rundoc::CodeCommand::Background
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class StdinWrite < Rundoc::CodeCommand
|
|
4
|
+
class StdinWriteArgs
|
|
5
|
+
attr_reader :contents, :name, :wait, :timeout, :ending
|
|
6
|
+
|
|
6
7
|
def initialize(contents, name:, wait:, timeout: 5, ending: $/)
|
|
7
8
|
@contents = contents
|
|
8
|
-
@ending = ending
|
|
9
|
-
@wait = wait
|
|
10
9
|
@name = name
|
|
11
|
-
@
|
|
10
|
+
@wait = wait
|
|
11
|
+
@timeout = Integer(timeout)
|
|
12
|
+
@ending = ending
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class StdinWriteRunner
|
|
17
|
+
attr_reader :contents
|
|
18
|
+
|
|
19
|
+
def initialize(user_args:, render_command:, render_result:, io: nil, contents: nil)
|
|
20
|
+
@contents = user_args.contents
|
|
21
|
+
@ending = user_args.ending
|
|
22
|
+
@wait = user_args.wait
|
|
23
|
+
@name = user_args.name
|
|
24
|
+
@timeout_value = user_args.timeout
|
|
12
25
|
@contents_written = nil
|
|
13
26
|
@background = nil
|
|
14
27
|
end
|
|
@@ -38,4 +51,4 @@ class Rundoc::CodeCommand::Background
|
|
|
38
51
|
end
|
|
39
52
|
end
|
|
40
53
|
end
|
|
41
|
-
Rundoc.register_code_command(:"background.stdin_write", Rundoc::CodeCommand::Background::
|
|
54
|
+
Rundoc.register_code_command(keyword: :"background.stdin_write", args_klass: Rundoc::CodeCommand::Background::StdinWriteArgs, runner_klass: Rundoc::CodeCommand::Background::StdinWriteRunner)
|
|
@@ -1,7 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
class Rundoc::CodeCommand::Background
|
|
2
|
-
class
|
|
4
|
+
class StopArgs
|
|
5
|
+
attr_reader :name
|
|
6
|
+
|
|
3
7
|
def initialize(name:)
|
|
4
8
|
@name = name
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class StopRunner
|
|
13
|
+
def initialize(user_args:, render_command:, render_result:, io: nil, contents: nil)
|
|
14
|
+
@name = user_args.name
|
|
5
15
|
@background = nil
|
|
6
16
|
end
|
|
7
17
|
|
|
@@ -19,4 +29,4 @@ class Rundoc::CodeCommand::Background
|
|
|
19
29
|
end
|
|
20
30
|
end
|
|
21
31
|
end
|
|
22
|
-
Rundoc.register_code_command(:"background.stop", Rundoc::CodeCommand::Background::
|
|
32
|
+
Rundoc.register_code_command(keyword: :"background.stop", args_klass: Rundoc::CodeCommand::Background::StopArgs, runner_klass: Rundoc::CodeCommand::Background::StopRunner)
|
|
@@ -1,9 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
class Rundoc::CodeCommand::Background
|
|
2
|
-
class
|
|
4
|
+
class WaitArgs
|
|
5
|
+
attr_reader :name, :wait, :timeout
|
|
6
|
+
|
|
3
7
|
def initialize(name:, wait:, timeout: 5)
|
|
4
8
|
@name = name
|
|
5
9
|
@wait = wait
|
|
6
|
-
@
|
|
10
|
+
@timeout = Integer(timeout)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class WaitRunner
|
|
15
|
+
def initialize(user_args:, render_command:, render_result:, io: nil, contents: nil)
|
|
16
|
+
@name = user_args.name
|
|
17
|
+
@wait = user_args.wait
|
|
18
|
+
@timeout_value = user_args.timeout
|
|
7
19
|
@background = nil
|
|
8
20
|
end
|
|
9
21
|
|
|
@@ -21,4 +33,4 @@ class Rundoc::CodeCommand::Background
|
|
|
21
33
|
end
|
|
22
34
|
end
|
|
23
35
|
end
|
|
24
|
-
Rundoc.register_code_command(:"background.wait", Rundoc::CodeCommand::Background::
|
|
36
|
+
Rundoc.register_code_command(keyword: :"background.wait", args_klass: Rundoc::CodeCommand::Background::WaitArgs, runner_klass: Rundoc::CodeCommand::Background::WaitRunner)
|
|
@@ -1,31 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Rundoc::CodeCommand::BashRunner
|
|
4
|
+
class Cd < Rundoc::CodeCommand::BashRunner
|
|
5
|
+
def initialize(line, io: $stdout)
|
|
6
|
+
@io = io
|
|
7
7
|
@line = line
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
capture_stderr = StringIO.new
|
|
14
|
-
$stderr = capture_stderr
|
|
10
|
+
def suppress_chdir_warning
|
|
11
|
+
old_verbose = $VERBOSE
|
|
12
|
+
$VERBOSE = nil
|
|
15
13
|
yield
|
|
16
14
|
ensure
|
|
17
|
-
|
|
18
|
-
$stderr = old_stderr
|
|
19
|
-
capture_string = capture_stderr.string
|
|
20
|
-
warn capture_string if capture_string.each_line.count > 1 || !capture_string.include?("conflicting chdir")
|
|
21
|
-
end
|
|
15
|
+
$VERBOSE = old_verbose
|
|
22
16
|
end
|
|
23
17
|
|
|
24
18
|
def call(env)
|
|
25
19
|
line = @line.sub("cd", "").strip
|
|
26
|
-
puts "running $ cd #{line}"
|
|
20
|
+
@io.puts "running $ cd #{line}"
|
|
27
21
|
|
|
28
|
-
|
|
22
|
+
suppress_chdir_warning do
|
|
29
23
|
Dir.chdir(line)
|
|
30
24
|
end
|
|
31
25
|
|
|
@@ -1,18 +1,32 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Rundoc::CodeCommand::BashArgs
|
|
4
|
+
attr_reader :line
|
|
5
|
+
|
|
5
6
|
def initialize(line)
|
|
6
7
|
@line = line
|
|
7
|
-
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class Rundoc::CodeCommand::BashRunner
|
|
12
|
+
attr_reader :io, :contents
|
|
13
|
+
|
|
14
|
+
def initialize(user_args:, render_command:, render_result:, io:, contents: nil)
|
|
15
|
+
@io = io
|
|
16
|
+
@contents = contents.dup if contents && !contents.empty?
|
|
17
|
+
@line = user_args.line
|
|
8
18
|
@delegate = case @line.split(" ").first.downcase
|
|
9
19
|
when "cd"
|
|
10
|
-
Cd.new(@line)
|
|
20
|
+
Cd.new(@line, io: io)
|
|
11
21
|
else
|
|
12
22
|
false
|
|
13
23
|
end
|
|
14
24
|
end
|
|
15
25
|
|
|
26
|
+
def raise_on_error?
|
|
27
|
+
true
|
|
28
|
+
end
|
|
29
|
+
|
|
16
30
|
def to_md(env = {})
|
|
17
31
|
return @delegate.to_md(env) if @delegate
|
|
18
32
|
|
|
@@ -34,30 +48,40 @@ class Rundoc::CodeCommand::Bash < Rundoc::CodeCommand
|
|
|
34
48
|
cmd = "(#{cmd}) 2>&1"
|
|
35
49
|
msg = "Running: $ '#{cmd}'"
|
|
36
50
|
msg << " with stdin: '#{stdin.inspect}'" if stdin && !stdin.empty?
|
|
37
|
-
puts msg
|
|
51
|
+
io.puts msg
|
|
38
52
|
|
|
39
|
-
result = ""
|
|
40
|
-
IO.popen(cmd, "w+") do |
|
|
41
|
-
|
|
42
|
-
|
|
53
|
+
result = +""
|
|
54
|
+
IO.popen(cmd, "w+") do |pipe|
|
|
55
|
+
pipe << stdin if stdin
|
|
56
|
+
pipe.close_write
|
|
43
57
|
|
|
44
|
-
until
|
|
45
|
-
buffer =
|
|
46
|
-
puts " #{buffer}"
|
|
58
|
+
until pipe.eof?
|
|
59
|
+
buffer = pipe.gets
|
|
60
|
+
io.puts " #{buffer}"
|
|
47
61
|
|
|
48
62
|
result << sanitize_escape_chars(buffer)
|
|
49
63
|
end
|
|
50
64
|
end
|
|
51
65
|
|
|
52
|
-
|
|
53
|
-
raise "Command `#{@line}` exited with non zero status: #{result}"
|
|
66
|
+
if raise_on_error? && !$?.success?
|
|
67
|
+
raise "Command `#{@line}` exited with non zero status: #{result}"
|
|
54
68
|
end
|
|
55
69
|
result
|
|
56
70
|
end
|
|
57
71
|
end
|
|
58
72
|
|
|
59
|
-
Rundoc
|
|
60
|
-
|
|
61
|
-
|
|
73
|
+
class Rundoc::CodeCommand::BashRunnerFailOk < Rundoc::CodeCommand::BashRunner
|
|
74
|
+
def raise_on_error?
|
|
75
|
+
false
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
Rundoc.register_code_command(keyword: :bash, args_klass: Rundoc::CodeCommand::BashArgs, runner_klass: Rundoc::CodeCommand::BashRunner)
|
|
80
|
+
Rundoc.register_code_command(keyword: :"$", args_klass: Rundoc::CodeCommand::BashArgs, runner_klass: Rundoc::CodeCommand::BashRunner)
|
|
81
|
+
Rundoc.register_code_command(
|
|
82
|
+
keyword: :"fail.$",
|
|
83
|
+
args_klass: Rundoc::CodeCommand::BashArgs,
|
|
84
|
+
runner_klass: Rundoc::CodeCommand::BashRunnerFailOk
|
|
85
|
+
)
|
|
62
86
|
|
|
63
87
|
require "rundoc/code_command/bash/cd"
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Rundoc::CodeCommand::CommentArgs
|
|
4
|
+
attr_reader :line
|
|
5
|
+
|
|
6
|
+
def initialize(line = nil)
|
|
7
|
+
@line = line
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class Rundoc::CodeCommand::CommentRunner
|
|
12
|
+
def initialize(user_args:, render_command:, render_result:, io:, contents: nil)
|
|
13
|
+
@io = io
|
|
14
|
+
@line = user_args&.line
|
|
15
|
+
@contents = contents
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def call(env = {})
|
|
19
|
+
@io.puts "Skipping command (commented out): # #{@line}\n#{@contents}".strip
|
|
20
|
+
""
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def to_md(env = {})
|
|
24
|
+
""
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
Rundoc.register_code_command(
|
|
29
|
+
keyword: :"#",
|
|
30
|
+
args_klass: Rundoc::CodeCommand::CommentArgs,
|
|
31
|
+
runner_klass: Rundoc::CodeCommand::CommentRunner,
|
|
32
|
+
always_hidden: true
|
|
33
|
+
)
|