pups 1.1.1 → 1.2.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 +37 -4
- data/CHANGELOG +4 -0
- data/README.md +28 -0
- data/lib/pups/cli.rb +43 -19
- data/lib/pups/command.rb +4 -2
- data/lib/pups/config.rb +110 -37
- data/lib/pups/docker.rb +5 -8
- data/lib/pups/exec_command.rb +46 -31
- data/lib/pups/file_command.rb +5 -7
- data/lib/pups/merge_command.rb +17 -14
- data/lib/pups/replace_command.rb +8 -8
- data/lib/pups/runit.rb +2 -6
- data/lib/pups/version.rb +1 -1
- data/lib/pups.rb +12 -14
- data/test/cli_test.rb +63 -12
- data/test/config_test.rb +102 -32
- data/test/docker_test.rb +52 -16
- data/test/exec_command_test.rb +26 -33
- data/test/file_command_test.rb +8 -9
- data/test/merge_command_test.rb +18 -15
- data/test/replace_command_test.rb +30 -31
- data/test/test_helper.rb +4 -4
- metadata +6 -7
- data/.github/workflows/lint.yml +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2474629aec1a6af05e0af5b4c87385bad16713e6fa86828f9233dd8140e5964f
|
4
|
+
data.tar.gz: 1bd85d9ed07b63633f9137aef9a7eae77537e05418eff260db5d1145ecbc999d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 22d164fcb61b5e36da7893731bd51bf11ed9732ecd4540be6912a26c2ddbbeb7ded0c6f1f2d07abea66217d4d18d02e08aa365c73ed588b15d139978a6ed77f6
|
7
|
+
data.tar.gz: d45150d87661548887be59363d7de3b069f8ed094a5ebb71da89d920b449adf3002f21b0788a9b2e87bcfd40f6bd1852ef27eae3f53e36a9966530087ae88e5c
|
data/.github/workflows/ci.yml
CHANGED
@@ -1,12 +1,30 @@
|
|
1
|
-
name:
|
1
|
+
name: CI
|
2
2
|
|
3
3
|
on:
|
4
4
|
push:
|
5
5
|
branches:
|
6
|
-
-
|
6
|
+
- main
|
7
7
|
pull_request: {}
|
8
8
|
|
9
9
|
jobs:
|
10
|
+
lint:
|
11
|
+
name: "pups lint"
|
12
|
+
runs-on: ${{ matrix.os }}
|
13
|
+
timeout-minutes: 5
|
14
|
+
|
15
|
+
strategy:
|
16
|
+
fail-fast: true
|
17
|
+
matrix:
|
18
|
+
os: [ubuntu-latest]
|
19
|
+
ruby: ["3.2"]
|
20
|
+
|
21
|
+
steps:
|
22
|
+
- uses: actions/checkout@v3
|
23
|
+
- uses: ruby/setup-ruby@v1
|
24
|
+
with:
|
25
|
+
ruby-version: ${{ matrix.ruby }}
|
26
|
+
bundler-cache: true
|
27
|
+
- run: bundle exec rubocop
|
10
28
|
test:
|
11
29
|
name: "pups tests"
|
12
30
|
runs-on: ${{ matrix.os }}
|
@@ -16,10 +34,10 @@ jobs:
|
|
16
34
|
fail-fast: true
|
17
35
|
matrix:
|
18
36
|
os: [ubuntu-latest]
|
19
|
-
ruby: ["2
|
37
|
+
ruby: ["3.2"]
|
20
38
|
|
21
39
|
steps:
|
22
|
-
- uses: actions/checkout@
|
40
|
+
- uses: actions/checkout@v3
|
23
41
|
- uses: ruby/setup-ruby@v1
|
24
42
|
with:
|
25
43
|
ruby-version: ${{ matrix.ruby }}
|
@@ -27,3 +45,18 @@ jobs:
|
|
27
45
|
- name: Run minitest
|
28
46
|
run: |
|
29
47
|
rake test
|
48
|
+
|
49
|
+
publish:
|
50
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
51
|
+
needs: [test]
|
52
|
+
runs-on: ubuntu-latest
|
53
|
+
|
54
|
+
steps:
|
55
|
+
- uses: actions/checkout@v3
|
56
|
+
|
57
|
+
- name: Release Gem
|
58
|
+
uses: discourse/publish-rubygems-action@v2
|
59
|
+
env:
|
60
|
+
RUBYGEMS_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
|
61
|
+
GIT_EMAIL: team@discourse.org
|
62
|
+
GIT_NAME: discoursebot
|
data/CHANGELOG
CHANGED
data/README.md
CHANGED
@@ -25,6 +25,8 @@ Usage: pups [options] [FILE|--stdin]
|
|
25
25
|
--stdin Read input from stdin.
|
26
26
|
--quiet Don't print any logs.
|
27
27
|
--ignore <elements> Ignore specific configuration elements, multiple elements can be provided (comma-delimited).
|
28
|
+
--tags <elements> Only run tagged commands.
|
29
|
+
--skip-tags <elements> Run all but listed tagged commands.
|
28
30
|
Useful if you want to skip over config in a pups execution.
|
29
31
|
e.g. `--ignore env,params`.
|
30
32
|
--gen-docker-run-args Output arguments from the pups configuration for input into a docker run command. All other pups config is ignored.
|
@@ -48,6 +50,32 @@ Running: `pups somefile.yaml` will execute the shell script resulting in a file
|
|
48
50
|
|
49
51
|
### Features
|
50
52
|
|
53
|
+
#### Filtering run commands by tags
|
54
|
+
|
55
|
+
The `--tags` and `--skip-tags` argument allows pups to target a subset of commands listed in the somefile.yaml. To use this, you may tag your commands in the runblock. `--tags` will only run commands when commands have a matching tag. `--skip-tags` will skip when commands have a matching tag.
|
56
|
+
|
57
|
+
Note, hooks from tagged commands will be present or absent depending on if the tag is filtered out or not as well. A command filtered out by targeting tag will also filter out the command's `before_` and `after_` hooks.
|
58
|
+
|
59
|
+
Example:
|
60
|
+
|
61
|
+
```
|
62
|
+
# somefile.yaml
|
63
|
+
|
64
|
+
run:
|
65
|
+
- exec:
|
66
|
+
cmd: /bin/bash -c 'echo hello >> hello'
|
67
|
+
tag: sometag
|
68
|
+
- exec:
|
69
|
+
cmd: /bin/bash -c 'echo hi >> hello'
|
70
|
+
tag: anothertag
|
71
|
+
- exec:
|
72
|
+
cmd: /bin/bash -c 'echo goodbye >> hello'
|
73
|
+
tag: thirdtag
|
74
|
+
```
|
75
|
+
Running: `pups --tags="sometag,anothertag" somefile.yaml` will not run the echo goodbye statement.
|
76
|
+
|
77
|
+
Running: `pups --skip-tags="sometag,anothertag" somefile.yaml` will ONLY run the echo goodbye statement.
|
78
|
+
|
51
79
|
#### Docker run argument generation
|
52
80
|
|
53
81
|
The `--gen-docker-run-args` argument is used to make pups output arguments be in the format of `docker run <arguments output>`. Specifically, pups
|
data/lib/pups/cli.rb
CHANGED
@@ -1,17 +1,30 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "optparse"
|
4
4
|
|
5
5
|
module Pups
|
6
6
|
class Cli
|
7
7
|
def self.opts
|
8
8
|
OptionParser.new do |opts|
|
9
|
-
opts.banner =
|
10
|
-
opts.on(
|
11
|
-
opts.on(
|
12
|
-
opts.on(
|
13
|
-
|
14
|
-
|
9
|
+
opts.banner = "Usage: pups [FILE|--stdin]"
|
10
|
+
opts.on("--stdin", "Read input from stdin.")
|
11
|
+
opts.on("--quiet", "Don't print any logs.")
|
12
|
+
opts.on(
|
13
|
+
"--ignore <element(s)>",
|
14
|
+
Array,
|
15
|
+
"Ignore these template configuration elements, multiple elements can be provided (comma-delimited)."
|
16
|
+
)
|
17
|
+
opts.on(
|
18
|
+
"--gen-docker-run-args",
|
19
|
+
"Output arguments from the pups configuration for input into a docker run command. All other pups config is ignored."
|
20
|
+
)
|
21
|
+
opts.on("--tags <tag(s)>", Array, "Only run tagged commands.")
|
22
|
+
opts.on(
|
23
|
+
"--skip-tags <tag(s)>",
|
24
|
+
Array,
|
25
|
+
"Run all but listed tagged commands."
|
26
|
+
)
|
27
|
+
opts.on("-h", "--help") do
|
15
28
|
puts opts
|
16
29
|
exit
|
17
30
|
end
|
@@ -26,35 +39,46 @@ module Pups
|
|
26
39
|
|
27
40
|
def self.run(args)
|
28
41
|
options = parse_args(args)
|
29
|
-
input_file = options[:stdin] ?
|
42
|
+
input_file = options[:stdin] ? "stdin" : args.last
|
30
43
|
unless input_file
|
31
44
|
puts opts.parse!(%w[--help])
|
32
45
|
exit
|
33
46
|
end
|
34
47
|
|
35
|
-
if options[:quiet]
|
36
|
-
Pups.silence
|
37
|
-
end
|
48
|
+
Pups.silence if options[:quiet]
|
38
49
|
|
39
50
|
Pups.log.info("Reading from #{input_file}")
|
40
51
|
|
41
52
|
if options[:stdin]
|
42
53
|
conf = $stdin.readlines.join
|
43
|
-
split = conf.split(
|
54
|
+
split = conf.split("_FILE_SEPERATOR_")
|
44
55
|
|
45
56
|
conf = nil
|
46
57
|
split.each do |data|
|
47
58
|
current = YAML.safe_load(data.strip)
|
48
|
-
conf =
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
59
|
+
conf =
|
60
|
+
if conf
|
61
|
+
Pups::MergeCommand.deep_merge(conf, current, :merge_arrays)
|
62
|
+
else
|
63
|
+
current
|
64
|
+
end
|
53
65
|
end
|
54
66
|
|
55
|
-
config =
|
67
|
+
config =
|
68
|
+
Pups::Config.new(
|
69
|
+
conf,
|
70
|
+
options[:ignore],
|
71
|
+
tags: options[:tags],
|
72
|
+
skip_tags: option[:"skip-tags"]
|
73
|
+
)
|
56
74
|
else
|
57
|
-
config =
|
75
|
+
config =
|
76
|
+
Pups::Config.load_file(
|
77
|
+
input_file,
|
78
|
+
options[:ignore],
|
79
|
+
tags: options[:tags],
|
80
|
+
skip_tags: options[:"skip-tags"]
|
81
|
+
)
|
58
82
|
end
|
59
83
|
|
60
84
|
if options[:"gen-docker-run-args"]
|
data/lib/pups/command.rb
CHANGED
@@ -4,8 +4,10 @@ module Pups
|
|
4
4
|
class Command
|
5
5
|
def self.run(command, params)
|
6
6
|
case command
|
7
|
-
when String
|
8
|
-
|
7
|
+
when String
|
8
|
+
from_str(command, params).run
|
9
|
+
when Hash
|
10
|
+
from_hash(command, params).run
|
9
11
|
end
|
10
12
|
end
|
11
13
|
|
data/lib/pups/config.rb
CHANGED
@@ -4,33 +4,59 @@ module Pups
|
|
4
4
|
class Config
|
5
5
|
attr_reader :config, :params
|
6
6
|
|
7
|
-
def initialize(
|
7
|
+
def initialize(
|
8
|
+
config,
|
9
|
+
ignored = nil,
|
10
|
+
tags: tags = nil,
|
11
|
+
skip_tags: skip_tags = nil
|
12
|
+
)
|
8
13
|
@config = config
|
9
14
|
|
10
15
|
# remove any ignored config elements prior to any more processing
|
11
16
|
ignored&.each { |e| @config.delete(e) }
|
12
17
|
|
18
|
+
filter_tags(include_tags: tags, exclude_tags: skip_tags)
|
19
|
+
|
13
20
|
# set some defaults to prevent checks in various functions
|
14
|
-
[
|
21
|
+
%w[env_template env labels params].each do |key|
|
22
|
+
@config[key] = {} unless @config.has_key?(key)
|
23
|
+
end
|
15
24
|
|
16
25
|
# Order here is important.
|
17
26
|
Pups::Config.combine_template_and_process_env(@config, ENV)
|
18
|
-
Pups::Config.prepare_env_template_vars(@config[
|
27
|
+
Pups::Config.prepare_env_template_vars(@config["env_template"], ENV)
|
19
28
|
|
20
29
|
# Templating is supported in env and label variables.
|
21
|
-
Pups::Config.transform_config_with_templated_vars(
|
22
|
-
|
23
|
-
|
30
|
+
Pups::Config.transform_config_with_templated_vars(
|
31
|
+
@config["env_template"],
|
32
|
+
ENV
|
33
|
+
)
|
34
|
+
Pups::Config.transform_config_with_templated_vars(
|
35
|
+
@config["env_template"],
|
36
|
+
@config["env"]
|
37
|
+
)
|
38
|
+
Pups::Config.transform_config_with_templated_vars(
|
39
|
+
@config["env_template"],
|
40
|
+
@config["labels"]
|
41
|
+
)
|
24
42
|
|
25
43
|
@params = @config["params"]
|
26
|
-
ENV.each
|
27
|
-
@params["$ENV_#{k}"] = v
|
28
|
-
end
|
44
|
+
ENV.each { |k, v| @params["$ENV_#{k}"] = v }
|
29
45
|
inject_hooks
|
30
46
|
end
|
31
47
|
|
32
|
-
def self.load_file(
|
33
|
-
|
48
|
+
def self.load_file(
|
49
|
+
config_file,
|
50
|
+
ignored = nil,
|
51
|
+
tags: tags = nil,
|
52
|
+
skip_tags: skip_tags = nil
|
53
|
+
)
|
54
|
+
Config.new(
|
55
|
+
YAML.load_file(config_file),
|
56
|
+
ignored,
|
57
|
+
tags: tags,
|
58
|
+
skip_tags: skip_tags
|
59
|
+
)
|
34
60
|
rescue Exception
|
35
61
|
warn "Failed to parse #{config_file}"
|
36
62
|
warn "This is probably a formatting error in #{config_file}"
|
@@ -38,15 +64,25 @@ module Pups
|
|
38
64
|
raise
|
39
65
|
end
|
40
66
|
|
41
|
-
def self.load_config(
|
42
|
-
|
67
|
+
def self.load_config(
|
68
|
+
config,
|
69
|
+
ignored = nil,
|
70
|
+
tags: tags = nil,
|
71
|
+
skip_tags: skip_tags = nil
|
72
|
+
)
|
73
|
+
Config.new(
|
74
|
+
YAML.safe_load(config),
|
75
|
+
ignored,
|
76
|
+
tags: tags,
|
77
|
+
skip_tags: skip_tags
|
78
|
+
)
|
43
79
|
end
|
44
80
|
|
45
81
|
def self.prepare_env_template_vars(env_template, env)
|
46
82
|
# Merge env_template variables from env and templates.
|
47
83
|
env.each do |k, v|
|
48
|
-
if k.include?(
|
49
|
-
key = k.gsub(
|
84
|
+
if k.include?("env_template_")
|
85
|
+
key = k.gsub("env_template_", "")
|
50
86
|
env_template[key] = v.to_s
|
51
87
|
end
|
52
88
|
end
|
@@ -70,10 +106,41 @@ module Pups
|
|
70
106
|
config["env"].each { |k, v| env[k] = v.to_s }
|
71
107
|
end
|
72
108
|
|
109
|
+
# Filter run commands by tag: by default, keep all commands that contain tags.
|
110
|
+
# If skip_tags argument is true, keep all commands that DO NOT contain tags.
|
111
|
+
def filter_tags(
|
112
|
+
include_tags: include_tags = nil,
|
113
|
+
exclude_tags: exclude_tags = nil
|
114
|
+
)
|
115
|
+
if include_tags
|
116
|
+
@config["run"] = @config["run"].select do |row|
|
117
|
+
keep = false
|
118
|
+
command = row.first
|
119
|
+
if command[1].is_a?(Hash)
|
120
|
+
tag = command[1]["tag"]
|
121
|
+
keep = include_tags.include?(tag)
|
122
|
+
end
|
123
|
+
keep
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
if exclude_tags
|
128
|
+
@config["run"] = @config["run"].select do |row|
|
129
|
+
keep = true
|
130
|
+
command = row.first
|
131
|
+
if command[1].is_a?(Hash)
|
132
|
+
tag = command[1]["tag"]
|
133
|
+
keep = !exclude_tags.include?(tag)
|
134
|
+
end
|
135
|
+
keep
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
73
140
|
def inject_hooks
|
74
|
-
return unless hooks = @config[
|
141
|
+
return unless hooks = @config["hooks"]
|
75
142
|
|
76
|
-
run = @config[
|
143
|
+
run = @config["run"]
|
77
144
|
|
78
145
|
positions = {}
|
79
146
|
run.each do |row|
|
@@ -81,7 +148,7 @@ module Pups
|
|
81
148
|
|
82
149
|
command = row.first
|
83
150
|
if command[1].is_a?(Hash)
|
84
|
-
hook = command[1][
|
151
|
+
hook = command[1]["hook"]
|
85
152
|
positions[hook] = row if hook
|
86
153
|
end
|
87
154
|
end
|
@@ -112,11 +179,11 @@ module Pups
|
|
112
179
|
|
113
180
|
def generate_docker_run_arguments
|
114
181
|
output = []
|
115
|
-
output << Pups::Docker.generate_env_arguments(config[
|
116
|
-
output << Pups::Docker.generate_link_arguments(config[
|
117
|
-
output << Pups::Docker.generate_expose_arguments(config[
|
118
|
-
output << Pups::Docker.generate_volume_arguments(config[
|
119
|
-
output << Pups::Docker.generate_label_arguments(config[
|
182
|
+
output << Pups::Docker.generate_env_arguments(config["env"])
|
183
|
+
output << Pups::Docker.generate_link_arguments(config["links"])
|
184
|
+
output << Pups::Docker.generate_expose_arguments(config["expose"])
|
185
|
+
output << Pups::Docker.generate_volume_arguments(config["volumes"])
|
186
|
+
output << Pups::Docker.generate_label_arguments(config["labels"])
|
120
187
|
output.sort!.join(" ").strip
|
121
188
|
end
|
122
189
|
|
@@ -128,25 +195,33 @@ module Pups
|
|
128
195
|
unless exit_code == 77
|
129
196
|
puts
|
130
197
|
puts
|
131
|
-
puts
|
132
|
-
puts
|
198
|
+
puts "FAILED"
|
199
|
+
puts "-" * 20
|
133
200
|
puts "#{e.class}: #{e}"
|
134
201
|
puts "Location of failure: #{e.backtrace[0]}"
|
135
|
-
|
202
|
+
if @last_command
|
203
|
+
puts "#{@last_command[:command]} failed with the params #{@last_command[:params].inspect}"
|
204
|
+
end
|
136
205
|
end
|
137
206
|
exit exit_code
|
138
207
|
end
|
139
208
|
|
140
209
|
def run_commands
|
141
|
-
@config[
|
210
|
+
@config["run"]&.each do |item|
|
142
211
|
item.each do |k, v|
|
143
|
-
type =
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
212
|
+
type =
|
213
|
+
case k
|
214
|
+
when "exec"
|
215
|
+
Pups::ExecCommand
|
216
|
+
when "merge"
|
217
|
+
Pups::MergeCommand
|
218
|
+
when "replace"
|
219
|
+
Pups::ReplaceCommand
|
220
|
+
when "file"
|
221
|
+
Pups::FileCommand
|
222
|
+
else
|
223
|
+
raise SyntaxError, "Invalid run command #{k}"
|
224
|
+
end
|
150
225
|
|
151
226
|
@last_command = { command: k, params: v }
|
152
227
|
type.run(v, @params)
|
@@ -162,9 +237,7 @@ module Pups
|
|
162
237
|
return unless cmd
|
163
238
|
|
164
239
|
processed = cmd.dup
|
165
|
-
params.each
|
166
|
-
processed.gsub!("$#{k}", v.to_s)
|
167
|
-
end
|
240
|
+
params.each { |k, v| processed.gsub!("$#{k}", v.to_s) }
|
168
241
|
processed
|
169
242
|
end
|
170
243
|
end
|
data/lib/pups/docker.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require
|
2
|
+
require "shellwords"
|
3
3
|
|
4
4
|
class Pups::Docker
|
5
5
|
class << self
|
@@ -16,7 +16,7 @@ class Pups::Docker
|
|
16
16
|
def generate_link_arguments(config)
|
17
17
|
output = []
|
18
18
|
config&.each do |c|
|
19
|
-
output << "--link #{c[
|
19
|
+
output << "--link #{c["link"]["name"]}:#{c["link"]["alias"]}"
|
20
20
|
end
|
21
21
|
normalize_output(output)
|
22
22
|
end
|
@@ -36,7 +36,7 @@ class Pups::Docker
|
|
36
36
|
def generate_volume_arguments(config)
|
37
37
|
output = []
|
38
38
|
config&.each do |c|
|
39
|
-
output << "--volume #{c[
|
39
|
+
output << "--volume #{c["volume"]["host"]}:#{c["volume"]["guest"]}"
|
40
40
|
end
|
41
41
|
normalize_output(output)
|
42
42
|
end
|
@@ -50,6 +50,7 @@ class Pups::Docker
|
|
50
50
|
end
|
51
51
|
|
52
52
|
private
|
53
|
+
|
53
54
|
def escape_user_string_literal(str)
|
54
55
|
# We need to escape the following strings as they are more likely to contain
|
55
56
|
# special characters than any of the other config variables on a Linux system:
|
@@ -59,11 +60,7 @@ class Pups::Docker
|
|
59
60
|
end
|
60
61
|
|
61
62
|
def normalize_output(output)
|
62
|
-
|
63
|
-
""
|
64
|
-
else
|
65
|
-
output.join(" ")
|
66
|
-
end
|
63
|
+
output.empty? ? "" : output.join(" ")
|
67
64
|
end
|
68
65
|
end
|
69
66
|
end
|
data/lib/pups/exec_command.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "timeout"
|
4
|
+
require "English"
|
5
5
|
|
6
6
|
module Pups
|
7
7
|
class ExecCommand < Pups::Command
|
@@ -9,12 +9,14 @@ module Pups
|
|
9
9
|
attr_accessor :background, :raise_on_fail, :stdin, :stop_signal
|
10
10
|
|
11
11
|
def self.terminate_async(opts = {})
|
12
|
-
return unless defined?
|
12
|
+
return unless defined?(@@asyncs)
|
13
13
|
|
14
|
-
Pups.log.info(
|
14
|
+
Pups.log.info("Terminating async processes")
|
15
15
|
|
16
16
|
@@asyncs.each do |async|
|
17
|
-
Pups.log.info(
|
17
|
+
Pups.log.info(
|
18
|
+
"Sending #{async[:stop_signal]} to #{async[:command]} pid: #{async[:pid]}"
|
19
|
+
)
|
18
20
|
begin
|
19
21
|
Process.kill(async[:stop_signal], async[:pid])
|
20
22
|
rescue StandardError
|
@@ -22,37 +24,43 @@ module Pups
|
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
25
|
-
@@asyncs
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
27
|
+
@@asyncs
|
28
|
+
.map do |async|
|
29
|
+
Thread.new do
|
30
|
+
Timeout.timeout(opts[:wait] || 10) do
|
31
|
+
Process.wait(async[:pid])
|
32
|
+
rescue StandardError
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
rescue Timeout::Error
|
36
|
+
Pups.log.info(
|
37
|
+
"#{async[:command]} pid:#{async[:pid]} did not terminate cleanly, forcing termination!"
|
38
|
+
)
|
39
|
+
begin
|
40
|
+
Process.kill("KILL", async[:pid])
|
41
|
+
Process.wait(async[:pid])
|
42
|
+
rescue Errno::ESRCH
|
43
|
+
rescue Errno::ECHILD
|
44
|
+
end
|
39
45
|
end
|
40
46
|
end
|
41
|
-
|
47
|
+
.each(&:join)
|
42
48
|
end
|
43
49
|
|
44
50
|
def self.from_hash(hash, params)
|
45
|
-
cmd = new(params, hash[
|
51
|
+
cmd = new(params, hash["cd"])
|
46
52
|
|
47
|
-
case c = hash[
|
48
|
-
when String
|
49
|
-
|
53
|
+
case c = hash["cmd"]
|
54
|
+
when String
|
55
|
+
cmd.add(c)
|
56
|
+
when Array
|
57
|
+
c.each { |i| cmd.add(i) }
|
50
58
|
end
|
51
59
|
|
52
|
-
cmd.background = hash[
|
53
|
-
cmd.stop_signal = hash[
|
54
|
-
cmd.raise_on_fail = hash[
|
55
|
-
cmd.stdin = interpolate_params(hash[
|
60
|
+
cmd.background = hash["background"]
|
61
|
+
cmd.stop_signal = hash["stop_signal"] || "TERM"
|
62
|
+
cmd.raise_on_fail = hash["raise_on_fail"] if hash.key? "raise_on_fail"
|
63
|
+
cmd.stdin = interpolate_params(hash["stdin"], params)
|
56
64
|
|
57
65
|
cmd
|
58
66
|
end
|
@@ -88,7 +96,11 @@ module Pups
|
|
88
96
|
def spawn(command)
|
89
97
|
if background
|
90
98
|
pid = Process.spawn(command)
|
91
|
-
(@@asyncs ||= []) << {
|
99
|
+
(@@asyncs ||= []) << {
|
100
|
+
pid: pid,
|
101
|
+
command: command,
|
102
|
+
stop_signal: (stop_signal || "TERM")
|
103
|
+
}
|
92
104
|
Thread.new do
|
93
105
|
begin
|
94
106
|
Process.wait(pid)
|
@@ -100,7 +112,7 @@ module Pups
|
|
100
112
|
return pid
|
101
113
|
end
|
102
114
|
|
103
|
-
IO.popen(command,
|
115
|
+
IO.popen(command, "w+") do |f|
|
104
116
|
if stdin
|
105
117
|
# need a way to get stdout without blocking
|
106
118
|
Pups.log.info(stdin)
|
@@ -112,7 +124,10 @@ module Pups
|
|
112
124
|
end
|
113
125
|
|
114
126
|
unless $CHILD_STATUS == 0
|
115
|
-
err =
|
127
|
+
err =
|
128
|
+
Pups::ExecError.new(
|
129
|
+
"#{command} failed with return #{$CHILD_STATUS.inspect}"
|
130
|
+
)
|
116
131
|
err.exit_code = $CHILD_STATUS.exitstatus
|
117
132
|
raise err
|
118
133
|
end
|
data/lib/pups/file_command.rb
CHANGED
@@ -6,10 +6,10 @@ module Pups
|
|
6
6
|
|
7
7
|
def self.from_hash(hash, params)
|
8
8
|
command = new
|
9
|
-
command.path = hash[
|
10
|
-
command.contents = hash[
|
11
|
-
command.chmod = hash[
|
12
|
-
command.chown = hash[
|
9
|
+
command.path = hash["path"]
|
10
|
+
command.contents = hash["contents"]
|
11
|
+
command.chmod = hash["chmod"]
|
12
|
+
command.chown = hash["chown"]
|
13
13
|
command.params = params
|
14
14
|
|
15
15
|
command
|
@@ -26,9 +26,7 @@ module Pups
|
|
26
26
|
path = interpolate_params(@path)
|
27
27
|
|
28
28
|
`mkdir -p #{File.dirname(path)}`
|
29
|
-
File.open(path,
|
30
|
-
f.write(interpolate_params(contents))
|
31
|
-
end
|
29
|
+
File.open(path, "w") { |f| f.write(interpolate_params(contents)) }
|
32
30
|
`chmod #{@chmod} #{path}` if @chmod
|
33
31
|
`chown #{@chown} #{path}` if @chown
|
34
32
|
Pups.log.info("File > #{path} chmod: #{@chmod} chown: #{@chown}")
|