pups 1.0.0 → 1.1.1
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 +5 -5
- data/.github/workflows/ci.yml +29 -0
- data/.github/workflows/lint.yml +27 -0
- data/.rubocop.yml +3 -0
- data/CHANGELOG +3 -0
- data/Gemfile +2 -0
- data/Guardfile +3 -1
- data/README.md +108 -29
- data/Rakefile +9 -3
- data/bin/pups +4 -4
- data/lib/pups.rb +25 -11
- data/lib/pups/cli.rb +61 -27
- data/lib/pups/command.rb +14 -11
- data/lib/pups/config.rb +139 -83
- data/lib/pups/docker.rb +69 -0
- data/lib/pups/exec_command.rb +93 -81
- data/lib/pups/file_command.rb +28 -28
- data/lib/pups/merge_command.rb +48 -46
- data/lib/pups/replace_command.rb +36 -34
- data/lib/pups/runit.rb +23 -24
- data/lib/pups/version.rb +3 -1
- data/pups.gemspec +21 -16
- data/test/cli_test.rb +117 -0
- data/test/config_test.rb +192 -30
- data/test/docker_test.rb +157 -0
- data/test/exec_command_test.rb +30 -34
- data/test/file_command_test.rb +8 -9
- data/test/merge_command_test.rb +32 -32
- data/test/replace_command_test.rb +42 -44
- data/test/test_helper.rb +4 -2
- metadata +80 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f5203de15040af48165295c4d93c85351b5995c137e9334566877a7875733f05
|
4
|
+
data.tar.gz: 6337c83523bc6e0e17d9f3ba494d62e7a629415a4ce75f95db8e92e998837993
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a4e356fde18db799f68049198eac4195a46c3d73f1919a66f473f195676a322a1759050bb01dfa6c447a4d705d6dce583bd6215e6a3412a339ffe55e2f57a48
|
7
|
+
data.tar.gz: 065473a360bac01f433757db10c513fc6790d49521218f6a3db5a55279386fa4ee89818c0aa16b07e37cc8f3375de705dae8fc9966191fabb2c17bf16675ad21
|
@@ -0,0 +1,29 @@
|
|
1
|
+
name: Tests
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- master
|
7
|
+
pull_request: {}
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
test:
|
11
|
+
name: "pups tests"
|
12
|
+
runs-on: ${{ matrix.os }}
|
13
|
+
timeout-minutes: 5
|
14
|
+
|
15
|
+
strategy:
|
16
|
+
fail-fast: true
|
17
|
+
matrix:
|
18
|
+
os: [ubuntu-latest]
|
19
|
+
ruby: ["2.7"]
|
20
|
+
|
21
|
+
steps:
|
22
|
+
- uses: actions/checkout@v2
|
23
|
+
- uses: ruby/setup-ruby@v1
|
24
|
+
with:
|
25
|
+
ruby-version: ${{ matrix.ruby }}
|
26
|
+
bundler-cache: true
|
27
|
+
- name: Run minitest
|
28
|
+
run: |
|
29
|
+
rake test
|
@@ -0,0 +1,27 @@
|
|
1
|
+
name: Lint
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- master
|
7
|
+
pull_request: {}
|
8
|
+
|
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: ["2.7"]
|
20
|
+
|
21
|
+
steps:
|
22
|
+
- uses: actions/checkout@v2
|
23
|
+
- uses: ruby/setup-ruby@v1
|
24
|
+
with:
|
25
|
+
ruby-version: ${{ matrix.ruby }}
|
26
|
+
bundler-cache: true
|
27
|
+
- run: bundle exec rubocop
|
data/.rubocop.yml
ADDED
data/CHANGELOG
ADDED
data/Gemfile
CHANGED
data/Guardfile
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
guard :minitest do
|
2
4
|
# with Minitest::Unit
|
3
|
-
watch(%r{^test/(.*)
|
5
|
+
watch(%r{^test/(.*)/?(.*)_test\.rb$})
|
4
6
|
watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[2]}_test.rb" }
|
5
7
|
watch(%r{^test/test_helper\.rb$}) { 'test' }
|
6
8
|
end
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# pups
|
2
2
|
|
3
|
-
Simple
|
3
|
+
Simple YAML--based bootstrapper
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -20,6 +20,19 @@ Or install it yourself as:
|
|
20
20
|
|
21
21
|
pups is a small library that allows you to automate the process of creating Unix images.
|
22
22
|
|
23
|
+
```
|
24
|
+
Usage: pups [options] [FILE|--stdin]
|
25
|
+
--stdin Read input from stdin.
|
26
|
+
--quiet Don't print any logs.
|
27
|
+
--ignore <elements> Ignore specific configuration elements, multiple elements can be provided (comma-delimited).
|
28
|
+
Useful if you want to skip over config in a pups execution.
|
29
|
+
e.g. `--ignore env,params`.
|
30
|
+
--gen-docker-run-args Output arguments from the pups configuration for input into a docker run command. All other pups config is ignored.
|
31
|
+
-h, --help
|
32
|
+
```
|
33
|
+
|
34
|
+
pups requires input either via a stdin stream or a filename. The entire input is parsed prior to any templating or command execution.
|
35
|
+
|
23
36
|
Example:
|
24
37
|
|
25
38
|
```
|
@@ -28,55 +41,78 @@ params:
|
|
28
41
|
hello: hello world
|
29
42
|
|
30
43
|
run:
|
31
|
-
exec: /bin/bash -c 'echo $hello
|
44
|
+
- exec: /bin/bash -c 'echo $hello >> hello'
|
32
45
|
```
|
33
46
|
|
34
|
-
Running: `pups somefile.yaml` will execute the shell script resulting in a file called "hello" with the "hello world"
|
47
|
+
Running: `pups somefile.yaml` will execute the shell script resulting in a file called "hello" with the contents "hello world".
|
48
|
+
|
49
|
+
### Features
|
35
50
|
|
36
|
-
|
51
|
+
#### Docker run argument generation
|
37
52
|
|
38
|
-
|
53
|
+
The `--gen-docker-run-args` argument is used to make pups output arguments be in the format of `docker run <arguments output>`. Specifically, pups
|
54
|
+
will take any `env`, `volume`, `labels`, `links`, and `expose` configuration, and coerce that into the format expected by `docker run`. This can be useful
|
55
|
+
when pups is being used to configure an image (e.g. by executing a series of commands) that is then going to be run as a container. That way, the runtime and image
|
56
|
+
configuration can be specified within the same yaml files.
|
57
|
+
|
58
|
+
|
59
|
+
#### Environment Variables
|
60
|
+
|
61
|
+
By default, pups automatically imports your environment variables and includes them as params.
|
62
|
+
|
63
|
+
```
|
64
|
+
# In bash
|
65
|
+
export SECRET_KEY="secret value"
|
66
|
+
|
67
|
+
# In somefile.yaml
|
68
|
+
run:
|
69
|
+
- exec: echo "$SECRET_KEY"
|
70
|
+
```
|
71
|
+
|
72
|
+
Running the above code with pups will produce `secret value`.
|
73
|
+
|
74
|
+
#### Execution
|
39
75
|
|
40
76
|
Run multiple commands in one path:
|
41
77
|
|
42
78
|
```
|
43
79
|
run:
|
44
|
-
exec:
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
80
|
+
- exec:
|
81
|
+
cd: some/path
|
82
|
+
cmd:
|
83
|
+
- echo 1
|
84
|
+
- echo 2
|
49
85
|
```
|
50
86
|
|
51
87
|
Run commands in the background (for services etc)
|
52
88
|
|
53
89
|
```
|
54
90
|
run:
|
55
|
-
exec:
|
56
|
-
|
57
|
-
|
58
|
-
```
|
91
|
+
- exec:
|
92
|
+
cmd: /usr/bin/sshd
|
93
|
+
background: true
|
94
|
+
```
|
59
95
|
|
60
96
|
Suppress exceptions on certain commands
|
61
97
|
|
62
98
|
```
|
63
99
|
run:
|
64
|
-
|
65
|
-
|
66
|
-
|
100
|
+
- exec:
|
101
|
+
cmd: /test
|
102
|
+
raise_on_fail: false
|
67
103
|
```
|
68
104
|
|
69
|
-
####Replacements:
|
105
|
+
#### Replacements:
|
70
106
|
|
71
107
|
```
|
72
108
|
run:
|
73
|
-
replace:
|
74
|
-
|
75
|
-
|
76
|
-
|
109
|
+
- replace:
|
110
|
+
filename: "/etc/redis/redis.conf"
|
111
|
+
from: /^pidfile.*$/
|
112
|
+
to: ""
|
77
113
|
```
|
78
114
|
|
79
|
-
Will
|
115
|
+
Will substitute the regex with blank, removing the pidfile line
|
80
116
|
|
81
117
|
```
|
82
118
|
run:
|
@@ -88,9 +124,34 @@ run:
|
|
88
124
|
}"
|
89
125
|
```
|
90
126
|
|
91
|
-
|
127
|
+
Additional params:
|
92
128
|
|
93
|
-
|
129
|
+
Global replace (as opposed to first match)
|
130
|
+
```
|
131
|
+
global: true
|
132
|
+
```
|
133
|
+
|
134
|
+
#### Hooks
|
135
|
+
|
136
|
+
Execute commands before and after a specific command by defining a hook.
|
137
|
+
|
138
|
+
```
|
139
|
+
run
|
140
|
+
- exec:
|
141
|
+
hook: hello
|
142
|
+
cmd: echo 'Hello'
|
143
|
+
|
144
|
+
hooks:
|
145
|
+
before_hello:
|
146
|
+
- exec:
|
147
|
+
cmd: echo 'Starting...'
|
148
|
+
|
149
|
+
after_hello:
|
150
|
+
- exec:
|
151
|
+
cmd: echo 'World'
|
152
|
+
```
|
153
|
+
|
154
|
+
#### Merge yaml files
|
94
155
|
|
95
156
|
```
|
96
157
|
home: /var/www/my_app
|
@@ -105,17 +166,35 @@ run:
|
|
105
166
|
|
106
167
|
```
|
107
168
|
|
108
|
-
Will merge the yaml file with the inline contents
|
169
|
+
Will merge the yaml file with the inline contents.
|
170
|
+
|
171
|
+
#### A common environment
|
172
|
+
|
173
|
+
Environment variables can be specified under the `env` key, which will be included in the environment for the template.
|
174
|
+
|
175
|
+
```
|
176
|
+
env:
|
177
|
+
MY_ENV: "a couple of words"
|
178
|
+
run:
|
179
|
+
- exec: echo $MY_ENV > tmpfile
|
180
|
+
```
|
181
|
+
|
182
|
+
`tmpfile` will contain `a couple of words`.
|
109
183
|
|
110
|
-
|
184
|
+
You can also specify variables to be templated within the environment, such as:
|
111
185
|
|
112
186
|
```
|
113
187
|
env:
|
114
|
-
|
188
|
+
greeting: "hello, {{location}}!"
|
189
|
+
env_template:
|
190
|
+
location: world
|
115
191
|
```
|
116
192
|
|
117
|
-
|
193
|
+
In this example, the `greeting` environment variable will be set to `hello, world!` during initialisation as the `{{location}}` variable will be templated as `world`.
|
194
|
+
Pups will also look in the environment itself at runtime for template variables, prefixed with `env_template_<variable name>`.
|
195
|
+
Note that strings should be quoted to prevent YAML from parsing the `{ }` characters.
|
118
196
|
|
197
|
+
All commands executed will inherit the environment once parsing and variable interpolation has been completed.
|
119
198
|
|
120
199
|
## Contributing
|
121
200
|
|
data/Rakefile
CHANGED
@@ -1,6 +1,12 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rake/testtask'
|
3
5
|
|
4
6
|
Rake::TestTask.new do |t|
|
5
|
-
t.
|
7
|
+
t.libs << 'test'
|
8
|
+
t.libs << 'lib'
|
9
|
+
t.test_files = FileList['test/*_test.rb']
|
6
10
|
end
|
11
|
+
|
12
|
+
task default: :test
|
data/bin/pups
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
|
-
$LOAD_PATH.unshift File.dirname(__FILE__)
|
4
|
+
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
|
4
5
|
|
5
|
-
require
|
6
|
-
require
|
6
|
+
require 'pups'
|
7
|
+
require 'pups/cli'
|
7
8
|
|
8
9
|
Pups::Cli.run(ARGV)
|
9
|
-
|
data/lib/pups.rb
CHANGED
@@ -1,23 +1,37 @@
|
|
1
|
-
|
2
|
-
require "yaml"
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require "pups/command"
|
7
|
-
require "pups/exec_command"
|
8
|
-
require "pups/merge_command"
|
9
|
-
require "pups/replace_command"
|
10
|
-
require "pups/file_command"
|
3
|
+
require 'logger'
|
4
|
+
require 'yaml'
|
11
5
|
|
12
|
-
require
|
6
|
+
require 'pups/version'
|
7
|
+
require 'pups/config'
|
8
|
+
require 'pups/command'
|
9
|
+
require 'pups/exec_command'
|
10
|
+
require 'pups/merge_command'
|
11
|
+
require 'pups/replace_command'
|
12
|
+
require 'pups/file_command'
|
13
|
+
require 'pups/docker'
|
14
|
+
require 'pups/runit'
|
13
15
|
|
14
16
|
module Pups
|
17
|
+
class ExecError < RuntimeError
|
18
|
+
attr_accessor :exit_code
|
19
|
+
end
|
20
|
+
|
15
21
|
def self.log
|
16
22
|
# at the moment docker likes this
|
17
|
-
@logger ||= Logger.new(
|
23
|
+
@logger ||= Logger.new($stderr)
|
18
24
|
end
|
19
25
|
|
20
26
|
def self.log=(logger)
|
21
27
|
@logger = logger
|
22
28
|
end
|
29
|
+
|
30
|
+
def self.silence
|
31
|
+
if @logger
|
32
|
+
@logger.close
|
33
|
+
end
|
34
|
+
|
35
|
+
@logger = Logger.new(File.open(File::NULL, "w"))
|
36
|
+
end
|
23
37
|
end
|
data/lib/pups/cli.rb
CHANGED
@@ -1,36 +1,70 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
puts "Usage: pups FILE or pups --stdin"
|
5
|
-
exit 1
|
6
|
-
end
|
7
|
-
def self.run(args)
|
8
|
-
if args.length != 1
|
9
|
-
usage
|
10
|
-
end
|
3
|
+
require 'optparse'
|
11
4
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
5
|
+
module Pups
|
6
|
+
class Cli
|
7
|
+
def self.opts
|
8
|
+
OptionParser.new do |opts|
|
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('--ignore <element(s)>', Array, "Ignore these template configuration elements, multiple elements can be provided (comma-delimited).")
|
13
|
+
opts.on('--gen-docker-run-args', 'Output arguments from the pups configuration for input into a docker run command. All other pups config is ignored.')
|
14
|
+
opts.on('-h', '--help') do
|
15
|
+
puts opts
|
16
|
+
exit
|
24
17
|
end
|
25
18
|
end
|
19
|
+
end
|
26
20
|
|
27
|
-
|
28
|
-
|
29
|
-
|
21
|
+
def self.parse_args(args)
|
22
|
+
options = {}
|
23
|
+
opts.parse!(args, into: options)
|
24
|
+
options
|
30
25
|
end
|
31
|
-
config.run
|
32
26
|
|
33
|
-
|
34
|
-
|
27
|
+
def self.run(args)
|
28
|
+
options = parse_args(args)
|
29
|
+
input_file = options[:stdin] ? 'stdin' : args.last
|
30
|
+
unless input_file
|
31
|
+
puts opts.parse!(%w[--help])
|
32
|
+
exit
|
33
|
+
end
|
34
|
+
|
35
|
+
if options[:quiet]
|
36
|
+
Pups.silence
|
37
|
+
end
|
38
|
+
|
39
|
+
Pups.log.info("Reading from #{input_file}")
|
40
|
+
|
41
|
+
if options[:stdin]
|
42
|
+
conf = $stdin.readlines.join
|
43
|
+
split = conf.split('_FILE_SEPERATOR_')
|
44
|
+
|
45
|
+
conf = nil
|
46
|
+
split.each do |data|
|
47
|
+
current = YAML.safe_load(data.strip)
|
48
|
+
conf = if conf
|
49
|
+
Pups::MergeCommand.deep_merge(conf, current, :merge_arrays)
|
50
|
+
else
|
51
|
+
current
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
config = Pups::Config.new(conf, options[:ignore])
|
56
|
+
else
|
57
|
+
config = Pups::Config.load_file(input_file, options[:ignore])
|
58
|
+
end
|
59
|
+
|
60
|
+
if options[:"gen-docker-run-args"]
|
61
|
+
print config.generate_docker_run_arguments
|
62
|
+
return
|
63
|
+
end
|
64
|
+
|
65
|
+
config.run
|
66
|
+
ensure
|
67
|
+
Pups::ExecCommand.terminate_async
|
68
|
+
end
|
35
69
|
end
|
36
70
|
end
|