fpm-fry 0.1.3 → 0.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/lib/cabin/nice_output.rb +11 -2
- data/lib/fpm/fry/channel.rb +23 -0
- data/lib/fpm/fry/client.rb +0 -25
- data/lib/fpm/fry/command/cook.rb +51 -24
- data/lib/fpm/fry/command.rb +17 -9
- data/lib/fpm/fry/detector.rb +13 -5
- data/lib/fpm/fry/docker_file.rb +8 -4
- data/lib/fpm/fry/plugin/config.rb +90 -0
- data/lib/fpm/fry/plugin/same_version.rb +19 -0
- data/lib/fpm/fry/plugin/service.rb +49 -4
- data/lib/fpm/fry/plugin/user.rb +21 -0
- data/lib/fpm/fry/recipe/builder.rb +21 -8
- data/lib/fpm/fry/recipe.rb +15 -2
- data/lib/fpm/fry/templates/sysv.erb +18 -1
- data/lib/fpm/fry/templates/upstart.erb +9 -0
- data/lib/fpm/fry/ui.rb +2 -1
- data/lib/fpm/package/docker.rb +1 -1
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9d58721a3f79317f65181422ff3a7e5d28ef823e
|
4
|
+
data.tar.gz: 85229c608182080d92b67b81c2e6d09f701d19ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5fc67b6dcbe5d6d8944028721665cbee9ae9bdb4f615c68812e012063e66c22ab278b943dc155d1e2ecc58e23021af133e8c0f29185db0ba0b5faa4f2dba5e5e
|
7
|
+
data.tar.gz: 03c12a7c8743715a8a33fff09c84e423ef67cbcd6a4a3a8659a6f7a1bd0b2e361797932117478950fb6ca6e5ac9af35049a4087c094a521b16a3e16a8d1fe22a
|
data/lib/cabin/nice_output.rb
CHANGED
@@ -6,14 +6,16 @@ class Cabin::NiceOutput
|
|
6
6
|
:red => "\e[1;31m",
|
7
7
|
:green => "\e[1;32m",
|
8
8
|
:yellow => "\e[0;33m",
|
9
|
-
:white => "\e[0;37m"
|
9
|
+
:white => "\e[0;37m",
|
10
|
+
:blue => "\e[1;34m"
|
10
11
|
}
|
11
12
|
|
12
13
|
DIM_CODEMAP = {
|
13
14
|
red: "\e[0;31m",
|
14
15
|
green: "\e[0;32m",
|
15
16
|
white: "\e[1;30m",
|
16
|
-
yellow: "\e[33m"
|
17
|
+
yellow: "\e[33m",
|
18
|
+
blue: "\e[0;34m"
|
17
19
|
}
|
18
20
|
|
19
21
|
LEVELMAP = {
|
@@ -21,6 +23,7 @@ class Cabin::NiceOutput
|
|
21
23
|
:error => :red,
|
22
24
|
:warn => :yellow,
|
23
25
|
:info => :green,
|
26
|
+
:hint => :blue,
|
24
27
|
:debug => :white,
|
25
28
|
}
|
26
29
|
|
@@ -43,6 +46,9 @@ class Cabin::NiceOutput
|
|
43
46
|
bold = data.delete(:bold) ? :bold : nil
|
44
47
|
|
45
48
|
backtrace = data.delete(:backtrace)
|
49
|
+
if !backtrace && data[:exception].respond_to?(:backtrace)
|
50
|
+
backtrace = data[:exception].backtrace
|
51
|
+
end
|
46
52
|
|
47
53
|
# Make 'error' and other log levels have color
|
48
54
|
if color.nil?
|
@@ -52,6 +58,9 @@ class Cabin::NiceOutput
|
|
52
58
|
message = [event[:level] ? '====> ' : ' ',event[:message]]
|
53
59
|
message.unshift(CODEMAP[color.to_sym]) if !color.nil?
|
54
60
|
message << DIM_CODEMAP[color] if !color.nil?
|
61
|
+
if documentation = data.delete(:documentation)
|
62
|
+
message << "\n\tRead more on this topic here: #{documentation}"
|
63
|
+
end
|
55
64
|
if data.any?
|
56
65
|
message << "\n" << pp(data)
|
57
66
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'cabin/channel'
|
2
|
+
module FPM; module Fry
|
3
|
+
class Channel < Cabin::Channel
|
4
|
+
|
5
|
+
module Hint
|
6
|
+
def hint( message, data = {} )
|
7
|
+
return unless hint?
|
8
|
+
log(message, data.merge(level: :hint))
|
9
|
+
end
|
10
|
+
|
11
|
+
def hint?
|
12
|
+
!defined?(@hint) || @hint
|
13
|
+
end
|
14
|
+
|
15
|
+
def hint=( bool )
|
16
|
+
@hint = !!bool
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
include Hint
|
21
|
+
|
22
|
+
end
|
23
|
+
end ; end
|
data/lib/fpm/fry/client.rb
CHANGED
@@ -9,30 +9,6 @@ module FPM; module Fry; end ; end
|
|
9
9
|
|
10
10
|
class FPM::Fry::Client
|
11
11
|
|
12
|
-
class LogInstrumentor < Struct.new(:logger)
|
13
|
-
|
14
|
-
def instrument(event, data = {})
|
15
|
-
if block_given?
|
16
|
-
logger.debug('Requesting HTTP', filtered(data))
|
17
|
-
r = yield
|
18
|
-
return r
|
19
|
-
else
|
20
|
-
logger.debug('Getting HTTP response', filtered(data))
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def filtered(data)
|
25
|
-
filtered = {}
|
26
|
-
filtered[:path] = data[:path] if data[:path]
|
27
|
-
filtered[:verb] = data[:method] if data[:method]
|
28
|
-
filtered[:status] = data[:status] if data[:status]
|
29
|
-
filtered[:body] = data[:body][0..500] if data[:body]
|
30
|
-
filtered[:headers] = data[:headers]
|
31
|
-
return filtered
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|
35
|
-
|
36
12
|
class FileNotFound < StandardError
|
37
13
|
end
|
38
14
|
|
@@ -141,7 +117,6 @@ class FPM::Fry::Client
|
|
141
117
|
def agent_for( uri, tls )
|
142
118
|
proto, address = uri.split('://',2)
|
143
119
|
options = {
|
144
|
-
instrumentor: LogInstrumentor.new(logger),
|
145
120
|
read_timeout: 10000
|
146
121
|
}.merge( tls )
|
147
122
|
case(proto)
|
data/lib/fpm/fry/command/cook.rb
CHANGED
@@ -18,10 +18,6 @@ module FPM; module Fry
|
|
18
18
|
parameter 'image', 'Docker image to build from'
|
19
19
|
parameter '[recipe]', 'Recipe file to cook', default: 'recipe.rb'
|
20
20
|
|
21
|
-
attr :ui
|
22
|
-
extend Forwardable
|
23
|
-
def_delegators :ui, :out, :err, :logger, :tmpdir
|
24
|
-
|
25
21
|
def initialize(invocation_path, ctx = {}, parent_attribute_values = {})
|
26
22
|
@tls = nil
|
27
23
|
require 'digest'
|
@@ -35,10 +31,6 @@ module FPM; module Fry
|
|
35
31
|
require 'fpm/fry/block_enumerator'
|
36
32
|
require 'fpm/fry/build_output_parser'
|
37
33
|
super
|
38
|
-
@ui = ctx.fetch(:ui){ UI.new }
|
39
|
-
if debug?
|
40
|
-
ui.logger.level = :debug
|
41
|
-
end
|
42
34
|
end
|
43
35
|
|
44
36
|
def detector
|
@@ -53,12 +45,8 @@ module FPM; module Fry
|
|
53
45
|
end
|
54
46
|
|
55
47
|
def detector=(d)
|
56
|
-
|
57
|
-
|
58
|
-
raise "Unable to detect distribution from given image"
|
59
|
-
end
|
60
|
-
rescue Excon::Errors::NotFound
|
61
|
-
raise "Image not found"
|
48
|
+
unless d.detect!
|
49
|
+
raise "Unable to detect distribution from given image"
|
62
50
|
end
|
63
51
|
@detector = d
|
64
52
|
end
|
@@ -70,7 +58,7 @@ module FPM; module Fry
|
|
70
58
|
|
71
59
|
def output_class
|
72
60
|
@output_class ||= begin
|
73
|
-
logger.
|
61
|
+
logger.debug("Autodetecting package type",flavour: flavour)
|
74
62
|
case(flavour)
|
75
63
|
when 'debian'
|
76
64
|
require 'fpm/package/deb'
|
@@ -92,7 +80,7 @@ module FPM; module Fry
|
|
92
80
|
distribution_version: detector.version,
|
93
81
|
flavour: flavour
|
94
82
|
}
|
95
|
-
logger.
|
83
|
+
logger.debug("Loading recipe",variables: vars, recipe: recipe)
|
96
84
|
b = Recipe::Builder.new(vars, Recipe.new, logger: ui.logger)
|
97
85
|
b.load_file( recipe )
|
98
86
|
b
|
@@ -150,7 +138,7 @@ module FPM; module Fry
|
|
150
138
|
'Content-Type'=>'application/tar'
|
151
139
|
},
|
152
140
|
expects: [200],
|
153
|
-
path: client.url("build?rm=1&t=#{cachetag}"),
|
141
|
+
path: client.url("build?rm=1&dockerfile=#{DockerFile::NAME}&t=#{cachetag}"),
|
154
142
|
request_block: BlockEnumerator.new(df.tar_io)
|
155
143
|
)
|
156
144
|
end
|
@@ -162,12 +150,12 @@ module FPM; module Fry
|
|
162
150
|
'Content-Type'=>'application/tar'
|
163
151
|
},
|
164
152
|
expects: [200],
|
165
|
-
path: client.url(
|
153
|
+
path: client.url("build?rm=1&dockerfile=#{DockerFile::NAME}"),
|
166
154
|
request_block: BlockEnumerator.new(df.tar_io),
|
167
155
|
response_block: parser
|
168
156
|
)
|
169
157
|
if parser.images.none?
|
170
|
-
raise "
|
158
|
+
raise "Didn't find a build image in the stream. This usually means that the build script failed."
|
171
159
|
end
|
172
160
|
image = parser.images.last
|
173
161
|
logger.debug("Detected build image", image: image)
|
@@ -191,13 +179,12 @@ module FPM; module Fry
|
|
191
179
|
begin
|
192
180
|
client.read( container, '/var/lib/apt/lists') do |file|
|
193
181
|
next if file.header.name == 'lists/'
|
194
|
-
logger.
|
195
|
-
return
|
182
|
+
logger.hint("/var/lib/apt/lists is not empty, you could try to speed up builds with --update=never", documentation: 'https://github.com/xing/fpm-fry/wiki/The-update-parameter')
|
183
|
+
return true
|
196
184
|
end
|
197
185
|
ensure
|
198
186
|
client.delete(path: client.url('containers',container))
|
199
187
|
end
|
200
|
-
logger.info("/var/lib/apt/lists is empty, update is required ( disable update with --apt-update=never )")
|
201
188
|
return true
|
202
189
|
when 'always'
|
203
190
|
return true
|
@@ -250,7 +237,7 @@ module FPM; module Fry
|
|
250
237
|
)
|
251
238
|
json = JSON.parse(res.body)
|
252
239
|
if json["StatusCode"] != 0
|
253
|
-
raise "Build failed"
|
240
|
+
raise "Build failed with exit code #{json["StatusCode"]}"
|
254
241
|
end
|
255
242
|
return yield container
|
256
243
|
ensure
|
@@ -283,6 +270,12 @@ module FPM; module Fry
|
|
283
270
|
|
284
271
|
output.output(tmp_package_file)
|
285
272
|
|
273
|
+
if output.config_files.any?
|
274
|
+
logger.debug("Found config files for #{output.name}", files: output.config_files)
|
275
|
+
else
|
276
|
+
logger.debug("No config files for #{output.name}")
|
277
|
+
end
|
278
|
+
|
286
279
|
begin
|
287
280
|
FileUtils.rm_rf package_file
|
288
281
|
rescue Errno::ENOENT
|
@@ -311,6 +304,7 @@ module FPM; module Fry
|
|
311
304
|
|
312
305
|
out_map.each do |output, package|
|
313
306
|
package.apply_output(output)
|
307
|
+
adjust_config_files(output)
|
314
308
|
end
|
315
309
|
|
316
310
|
out_map.each do |output, _|
|
@@ -327,6 +321,39 @@ module FPM; module Fry
|
|
327
321
|
end
|
328
322
|
|
329
323
|
|
324
|
+
def adjust_config_files( output )
|
325
|
+
# FPM flags all files in /etc as config files but only for debian :/.
|
326
|
+
# Actually this behavior makes sense to me for all packages because it's
|
327
|
+
# the thing I usually want. By setting this attribute at least the
|
328
|
+
# misleading warning goes away.
|
329
|
+
output.attributes[:deb_no_default_config_files?] = true
|
330
|
+
output.attributes[:deb_auto_config_files?] = false
|
331
|
+
|
332
|
+
return if output.attributes[:fry_config_explicitly_used]
|
333
|
+
|
334
|
+
# Now that we have disabled this for debian we have to reenable if it for
|
335
|
+
# all.
|
336
|
+
etc = File.expand_path('etc', output.staging_path)
|
337
|
+
if File.exists?( etc )
|
338
|
+
# Config plugin wasn't used. Add everything under /etc
|
339
|
+
prefix_length = output.staging_path.size + 1
|
340
|
+
added = []
|
341
|
+
Find.find(etc) do | path |
|
342
|
+
next unless File.file? path
|
343
|
+
name = path[prefix_length..-1]
|
344
|
+
if !output.config_files.include? name
|
345
|
+
added << name
|
346
|
+
output.config_files << name
|
347
|
+
end
|
348
|
+
end
|
349
|
+
if added.any?
|
350
|
+
logger.hint( "#{output.name} contains some config files in /etc. They were automatically added. You can customize this using the \"config\" plugin.",
|
351
|
+
documentation: "https://github.com/xing/fpm-fry/wiki/Plugin-config",
|
352
|
+
files: added)
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
330
357
|
public
|
331
358
|
|
332
359
|
def execute
|
@@ -355,7 +382,7 @@ module FPM; module Fry
|
|
355
382
|
|
356
383
|
return 0
|
357
384
|
rescue Recipe::NotFound => e
|
358
|
-
logger.error("Recipe not found", recipe: recipe,
|
385
|
+
logger.error("Recipe not found", recipe: recipe, exception: e)
|
359
386
|
return 1
|
360
387
|
rescue => e
|
361
388
|
logger.error(e)
|
data/lib/fpm/fry/command.rb
CHANGED
@@ -16,13 +16,29 @@ module FPM; module Fry
|
|
16
16
|
|
17
17
|
subcommand 'fpm', 'Works like fpm but with docker support', FPM::Command
|
18
18
|
|
19
|
+
attr :ui
|
20
|
+
extend Forwardable
|
21
|
+
def_delegators :ui, :out, :err, :logger, :tmpdir
|
22
|
+
|
23
|
+
def initialize(invocation_path, ctx = {}, parent_attribute_values = {})
|
24
|
+
super
|
25
|
+
@ui = ctx.fetch(:ui){ UI.new }
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse(attrs)
|
29
|
+
super
|
30
|
+
if debug?
|
31
|
+
ui.logger.level = :debug
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
19
35
|
def client
|
20
36
|
@client ||= begin
|
21
37
|
client = FPM::Fry::Client.new(
|
22
38
|
logger: logger,
|
23
39
|
tls: tls?, tlsverify: tlsverify?
|
24
40
|
)
|
25
|
-
logger.
|
41
|
+
logger.debug("Docker connected",client.server_version)
|
26
42
|
client
|
27
43
|
end
|
28
44
|
end
|
@@ -39,14 +55,6 @@ module FPM; module Fry
|
|
39
55
|
extend Forwardable
|
40
56
|
def_delegators :ui, :logger
|
41
57
|
|
42
|
-
def initialize(*_)
|
43
|
-
super
|
44
|
-
@ui = UI.new()
|
45
|
-
if debug?
|
46
|
-
ui.logger.level = :debug
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
58
|
def execute
|
51
59
|
require 'fpm/fry/os_db'
|
52
60
|
require 'fpm/fry/detector'
|
data/lib/fpm/fry/detector.rb
CHANGED
@@ -73,6 +73,10 @@ module FPM; module Fry
|
|
73
73
|
end
|
74
74
|
|
75
75
|
class Image < Struct.new(:client,:image,:factory)
|
76
|
+
|
77
|
+
class ImageNotFound < StandardError
|
78
|
+
end
|
79
|
+
|
76
80
|
attr :distribution
|
77
81
|
attr :version
|
78
82
|
|
@@ -82,11 +86,15 @@ module FPM; module Fry
|
|
82
86
|
|
83
87
|
def detect!
|
84
88
|
body = JSON.generate({"Image" => image, "Cmd" => "exit 0"})
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
89
|
+
begin
|
90
|
+
res = client.post( path: client.url('containers','create'),
|
91
|
+
headers: {'Content-Type' => 'application/json'},
|
92
|
+
body: body,
|
93
|
+
expects: [201]
|
94
|
+
)
|
95
|
+
rescue Excon::Errors::NotFound
|
96
|
+
raise ImageNotFound, "Image #{image.inspect} not found. Did you do a `docker pull #{image}` before?"
|
97
|
+
end
|
90
98
|
body = JSON.parse(res.body)
|
91
99
|
container = body.fetch('Id')
|
92
100
|
begin
|
data/lib/fpm/fry/docker_file.rb
CHANGED
@@ -7,6 +7,8 @@ require 'fpm/fry/joined_io'
|
|
7
7
|
module FPM; module Fry
|
8
8
|
class DockerFile < Struct.new(:variables,:cache,:recipe)
|
9
9
|
|
10
|
+
NAME = 'Dockerfile.fpm-fry'
|
11
|
+
|
10
12
|
class Source < Struct.new(:variables, :cache)
|
11
13
|
|
12
14
|
def initialize(variables, cache = Source::Null::Cache)
|
@@ -42,7 +44,7 @@ module FPM; module Fry
|
|
42
44
|
def self_tar_io
|
43
45
|
sio = StringIO.new
|
44
46
|
tar = Gem::Package::TarWriter.new(sio)
|
45
|
-
tar.add_file(
|
47
|
+
tar.add_file(NAME,'0777') do |io|
|
46
48
|
io.write(dockerfile)
|
47
49
|
end
|
48
50
|
#tar.close
|
@@ -122,8 +124,10 @@ module FPM; module Fry
|
|
122
124
|
def build_sh
|
123
125
|
df = ['#!/bin/bash']
|
124
126
|
df << 'set -e'
|
125
|
-
recipe.steps.each do |
|
126
|
-
|
127
|
+
recipe.steps.each do |v|
|
128
|
+
if v.respond_to? :name
|
129
|
+
df << "echo -e '\\e[1;32m====> #{Shellwords.escape v.name}\\e[0m'"
|
130
|
+
end
|
127
131
|
df << v.to_s
|
128
132
|
end
|
129
133
|
df << ''
|
@@ -136,7 +140,7 @@ module FPM; module Fry
|
|
136
140
|
tar.add_file('.build.sh','0777') do |io|
|
137
141
|
io.write(build_sh)
|
138
142
|
end
|
139
|
-
tar.add_file(
|
143
|
+
tar.add_file(NAME,'0777') do |io|
|
140
144
|
io.write(dockerfile)
|
141
145
|
end
|
142
146
|
#tar.close
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'fpm/fry/plugin'
|
2
|
+
module FPM::Fry::Plugin::Config
|
3
|
+
|
4
|
+
# @api private
|
5
|
+
IMPLICIT = Module.new
|
6
|
+
|
7
|
+
# @api private
|
8
|
+
MARK_EXPLICIT = Module.new do
|
9
|
+
def self.call(_, package)
|
10
|
+
package.attributes[:fry_config_explicitly_used] = true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# @api private
|
15
|
+
class Callback < Struct.new(:files)
|
16
|
+
|
17
|
+
def call(_, package)
|
18
|
+
prefix_length = package.staging_path.size + 1
|
19
|
+
candidates = []
|
20
|
+
# Sorting is important so that more specific rules override more generic
|
21
|
+
# rules.
|
22
|
+
keys = files.keys.sort_by(&:size)
|
23
|
+
keys.each do | key |
|
24
|
+
if files[key]
|
25
|
+
# Inclusion rule. Crawl file system for candidates
|
26
|
+
Find.find( File.expand_path(key, package.staging_path) ) do | path |
|
27
|
+
next unless File.file? path
|
28
|
+
name = path[prefix_length..-1]
|
29
|
+
candidates << name
|
30
|
+
end
|
31
|
+
else
|
32
|
+
# Exclusion rule. Remove matching candidates
|
33
|
+
keydir = key + "/"
|
34
|
+
candidates.reject!{ |can|
|
35
|
+
can.start_with?(keydir) || can == key
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
package.config_files |= candidates
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
class DSL < Struct.new(:builder, :options, :callback)
|
45
|
+
|
46
|
+
def initialize( builder, options )
|
47
|
+
callback = builder.output_hooks.find{|h| h.kind_of? Callback }
|
48
|
+
if !callback
|
49
|
+
callback = Callback.new({'etc' => true})
|
50
|
+
builder.output_hooks << callback
|
51
|
+
end
|
52
|
+
# This looks kind of dirty. The callback tells the cook comamnd that the
|
53
|
+
# user has explictly used the config plugin. This way the cook command
|
54
|
+
# can hint the user to use this plugin if config files were automatically
|
55
|
+
# added.
|
56
|
+
if !options[IMPLICIT]
|
57
|
+
builder.output_hooks << MARK_EXPLICIT
|
58
|
+
end
|
59
|
+
super( builder, options, callback )
|
60
|
+
end
|
61
|
+
|
62
|
+
def include( path )
|
63
|
+
if path[0] == "/"
|
64
|
+
path = path[1..-1]
|
65
|
+
end
|
66
|
+
callback.files[path] = true
|
67
|
+
end
|
68
|
+
|
69
|
+
def exclude( path )
|
70
|
+
if path[0] == "/"
|
71
|
+
path = path[1..-1]
|
72
|
+
end
|
73
|
+
callback.files[path] = false
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.apply( builder, options = {}, &block )
|
79
|
+
dsl = DSL.new(builder, options)
|
80
|
+
if block
|
81
|
+
if block.arity == 1
|
82
|
+
yield dsl
|
83
|
+
else
|
84
|
+
dsl.instance_eval(&block)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
dsl
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module FPM::Fry::Plugin::SameVersion
|
2
|
+
|
3
|
+
# Generates a special constraint that ignores iterations.
|
4
|
+
# This is especially pointful in multi-package recipes.
|
5
|
+
# @example
|
6
|
+
# name 'mainpackage'
|
7
|
+
# version '0.2.3'
|
8
|
+
# package 'subpackage'
|
9
|
+
# plugin 'same_version'
|
10
|
+
# depends 'mainpackage', same_version
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
def same_version
|
14
|
+
*head, last = version.split('.')
|
15
|
+
last = last.to_i + 1
|
16
|
+
return ">= #{version}, << #{head.join '.'}.#{last}"
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -1,29 +1,39 @@
|
|
1
1
|
require 'fpm/fry/plugin'
|
2
2
|
require 'fpm/fry/plugin/init'
|
3
3
|
require 'fpm/fry/plugin/edit_staging'
|
4
|
+
require 'fpm/fry/plugin/config'
|
4
5
|
require 'erb'
|
5
6
|
require 'shellwords'
|
6
7
|
module FPM::Fry::Plugin ; module Service
|
7
8
|
|
8
|
-
class Environment < Struct.new(:name,:command, :description)
|
9
|
+
class Environment < Struct.new(:name,:command, :description, :limits, :user, :group, :chdir)
|
9
10
|
|
10
11
|
def render(file)
|
11
12
|
_erbout = ""
|
12
13
|
erb = ERB.new(
|
13
|
-
IO.read(File.join(File.dirname(__FILE__),'..','templates',file))
|
14
|
+
IO.read(File.join(File.dirname(__FILE__),'..','templates',file)),
|
15
|
+
0, "-"
|
14
16
|
)
|
15
|
-
eval(erb.src)
|
17
|
+
eval(erb.src,nil,File.join(File.dirname(__FILE__),'..','templates',file))
|
16
18
|
return _erbout
|
17
19
|
end
|
18
20
|
|
19
21
|
end
|
20
22
|
|
23
|
+
LIMITS = %w(core cpu data fsize memlock msgqueue nice nofile nproc rss rtprio sigpending stack)
|
24
|
+
|
21
25
|
class DSL
|
22
26
|
|
27
|
+
attr :limits
|
28
|
+
|
23
29
|
def initialize(*_)
|
24
30
|
super
|
25
31
|
@name = nil
|
26
32
|
@command = []
|
33
|
+
@limits = {}
|
34
|
+
@user = nil
|
35
|
+
@group = nil
|
36
|
+
@chdir = nil
|
27
37
|
end
|
28
38
|
|
29
39
|
def name( n = nil )
|
@@ -33,6 +43,34 @@ module FPM::Fry::Plugin ; module Service
|
|
33
43
|
return @name
|
34
44
|
end
|
35
45
|
|
46
|
+
def group( n = nil )
|
47
|
+
if n
|
48
|
+
@group = n
|
49
|
+
end
|
50
|
+
return @group
|
51
|
+
end
|
52
|
+
|
53
|
+
def user( n = nil )
|
54
|
+
if n
|
55
|
+
@user = n
|
56
|
+
end
|
57
|
+
return @user
|
58
|
+
end
|
59
|
+
|
60
|
+
def limit( name, soft, hard = soft )
|
61
|
+
unless LIMITS.include? name
|
62
|
+
raise ArgumentError, "Unknown limit #{name.inspect}. Known limits are: #{LIMITS.inspect}"
|
63
|
+
end
|
64
|
+
@limits[name] = [soft,hard]
|
65
|
+
end
|
66
|
+
|
67
|
+
def chdir( dir = nil )
|
68
|
+
if dir
|
69
|
+
@chdir = dir
|
70
|
+
end
|
71
|
+
@chdir
|
72
|
+
end
|
73
|
+
|
36
74
|
def command( *args )
|
37
75
|
if args.any?
|
38
76
|
@command = args
|
@@ -45,7 +83,7 @@ module FPM::Fry::Plugin ; module Service
|
|
45
83
|
name = self.name || builder.name || raise
|
46
84
|
init = Init.detect_init(builder.variables)
|
47
85
|
edit = builder.plugin('edit_staging')
|
48
|
-
env = Environment.new(name, command, "")
|
86
|
+
env = Environment.new(name, command, "", @limits, @user, @group, @chdir)
|
49
87
|
case(init)
|
50
88
|
when 'upstart' then
|
51
89
|
edit.add_file "/etc/init/#{name}.conf",StringIO.new( env.render('upstart.erb') )
|
@@ -64,6 +102,10 @@ if status #{Shellwords.shellescape name} 2>/dev/null | grep -q ' start/'; then
|
|
64
102
|
fi
|
65
103
|
BASH
|
66
104
|
end
|
105
|
+
builder.plugin('config', FPM::Fry::Plugin::Config::IMPLICIT => true) do |co|
|
106
|
+
co.include "etc/init/#{name}.conf"
|
107
|
+
co.include "etc/init.d/#{name}"
|
108
|
+
end
|
67
109
|
when 'sysv' then
|
68
110
|
edit.add_file "/etc/init.d/#{name}",StringIO.new( env.render('sysv.erb') ), chmod: '750'
|
69
111
|
builder.plugin('script_helper') do |sh|
|
@@ -76,6 +118,9 @@ BASH
|
|
76
118
|
update-rc.d -f #{Shellwords.shellescape name} remove
|
77
119
|
BASH
|
78
120
|
end
|
121
|
+
builder.plugin('config', FPM::Fry::Plugin::Config::IMPLICIT => true) do |co|
|
122
|
+
co.include "etc/init.d/#{name}"
|
123
|
+
end
|
79
124
|
when 'systemd' then
|
80
125
|
|
81
126
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'fpm/fry/plugin'
|
2
|
+
module FPM::Fry::Plugin ; module User
|
3
|
+
|
4
|
+
def self.apply(builder, name, options = {}, &block)
|
5
|
+
cmd = ["adduser", "--system"]
|
6
|
+
case options[:group]
|
7
|
+
when String
|
8
|
+
cmd << '--ingroup' << options[:group]
|
9
|
+
when true
|
10
|
+
cmd << '--group'
|
11
|
+
when nil
|
12
|
+
else
|
13
|
+
raise ArgumentError, ":group must be a String or true, got #{options[:group].inspect}"
|
14
|
+
end
|
15
|
+
cmd << name
|
16
|
+
builder.plugin('script_helper') do |sh|
|
17
|
+
sh.after_install_or_upgrade(Shellwords.shelljoin(cmd))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end ; end
|
@@ -86,6 +86,9 @@ module FPM::Fry
|
|
86
86
|
if mod.respond_to? :apply
|
87
87
|
mod.apply(self, *args, &block)
|
88
88
|
else
|
89
|
+
if args.any? or block_given?
|
90
|
+
raise ArgumentError, "Simple plugins can't accept additional arguments and blocks."
|
91
|
+
end
|
89
92
|
extend(mod)
|
90
93
|
end
|
91
94
|
end
|
@@ -131,14 +134,16 @@ module FPM::Fry
|
|
131
134
|
|
132
135
|
def parse_package( name, options = {} )
|
133
136
|
if options.kind_of? String
|
134
|
-
options = {
|
137
|
+
options = {constraints: options}
|
135
138
|
end
|
136
|
-
case(v = options[:
|
139
|
+
case(v = options[:constraints])
|
137
140
|
when String
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
141
|
+
options[:constraints] = v.split(',').map do |c|
|
142
|
+
if c =~ /\A\s*(<=|<<|>=|>>|<>|=|>|<)(\s*)/
|
143
|
+
$1 + ' ' + $'
|
144
|
+
else
|
145
|
+
'= ' + c
|
146
|
+
end
|
142
147
|
end
|
143
148
|
end
|
144
149
|
return name, options
|
@@ -202,8 +207,16 @@ module FPM::Fry
|
|
202
207
|
options = {}
|
203
208
|
end
|
204
209
|
command = args.shift
|
205
|
-
name = options.fetch(:name){ [command,*args].select{|c| c[0] != '-' }.join('
|
206
|
-
|
210
|
+
name = options.fetch(:name){ [command,*args].select{|c| c[0] != '-' }.join(' ') }
|
211
|
+
bash( name, Shellwords.join([command, *args]) )
|
212
|
+
end
|
213
|
+
|
214
|
+
def bash( name = nil, code )
|
215
|
+
if name
|
216
|
+
recipe.steps << Recipe::Step.new(name, code)
|
217
|
+
else
|
218
|
+
recipe.steps << code.to_s
|
219
|
+
end
|
207
220
|
end
|
208
221
|
|
209
222
|
def build_depends( name , options = {} )
|
data/lib/fpm/fry/recipe.rb
CHANGED
@@ -12,6 +12,12 @@ module FPM; module Fry
|
|
12
12
|
|
13
13
|
class Recipe
|
14
14
|
|
15
|
+
class Step < Struct.new(:name, :value)
|
16
|
+
def to_s
|
17
|
+
value.to_s
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
15
21
|
class PackageRecipe
|
16
22
|
attr_accessor :name,
|
17
23
|
:iteration,
|
@@ -62,7 +68,14 @@ module FPM; module Fry
|
|
62
68
|
end
|
63
69
|
[:dependencies, :conflicts, :replaces, :provides].each do |sym|
|
64
70
|
send(sym).each do |name, options|
|
65
|
-
|
71
|
+
constr = Array(options[:constraints])
|
72
|
+
if constr.any?
|
73
|
+
constr.each do | c |
|
74
|
+
package.send(sym) << "#{name} #{c}"
|
75
|
+
end
|
76
|
+
else
|
77
|
+
package.send(sym) << name
|
78
|
+
end
|
66
79
|
end
|
67
80
|
end
|
68
81
|
output_hooks.each{|h| h.call(self, package) }
|
@@ -112,7 +125,7 @@ module FPM; module Fry
|
|
112
125
|
|
113
126
|
def initialize
|
114
127
|
@source = Source::Null
|
115
|
-
@steps =
|
128
|
+
@steps = []
|
116
129
|
@packages = [PackageRecipe.new]
|
117
130
|
@packages[0].files << '**'
|
118
131
|
@build_depends = {}
|
@@ -1,4 +1,21 @@
|
|
1
1
|
#!/bin/sh
|
2
|
+
<%
|
3
|
+
startopts = ['']
|
4
|
+
if user
|
5
|
+
if group
|
6
|
+
startopts << '-c' << Shellwords.escape(user + ':' + group)
|
7
|
+
else
|
8
|
+
startopts << '-c' << Shellwords.escape(user)
|
9
|
+
end
|
10
|
+
else
|
11
|
+
if group
|
12
|
+
startopts << '-g' << Shellwords.escape(group)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
if chdir
|
16
|
+
startopts << '-d' << Shellwords.escape(chdir)
|
17
|
+
end
|
18
|
+
-%>
|
2
19
|
### BEGIN INIT INFO
|
3
20
|
# Provides: <%= name %>
|
4
21
|
# Required-Start: $remote_fs $syslog
|
@@ -42,7 +59,7 @@ do_start()
|
|
42
59
|
# 2 if daemon could not be started
|
43
60
|
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
|
44
61
|
|| return 1
|
45
|
-
start-stop-daemon --start --quiet --pidfile $PIDFILE --background --exec $DAEMON -- \
|
62
|
+
start-stop-daemon --start --quiet --pidfile $PIDFILE --background<%= startopts.join(" ") %> --exec $DAEMON -- \
|
46
63
|
$DAEMON_ARGS \
|
47
64
|
|| return 2
|
48
65
|
# Add code here, if necessary, that waits for the process to be ready
|
@@ -7,6 +7,15 @@ env NAME=<%= name.inspect %>
|
|
7
7
|
env DAEMON=<%= command[0].inspect %>
|
8
8
|
env DAEMON_ARGS=<%= Shellwords.shelljoin(command[1..-1]).inspect %>
|
9
9
|
|
10
|
+
<% if user %>setuid <%= user.inspect %>
|
11
|
+
<% end -%>
|
12
|
+
<% if group %>setgid <%= group.inspect %>
|
13
|
+
<% end -%>
|
14
|
+
<% if chdir %>chdir <%= chdir.inspect %>
|
15
|
+
<% end -%>
|
16
|
+
<% limits.each do | name, (soft, hard) | -%>
|
17
|
+
limit <%= name %> <%= soft %> <%= hard %>
|
18
|
+
<% end -%>
|
10
19
|
respawn
|
11
20
|
|
12
21
|
script
|
data/lib/fpm/fry/ui.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'cabin/nice_output'
|
2
|
+
require 'fpm/fry/channel'
|
2
3
|
module FPM; module Fry
|
3
4
|
class UI < Struct.new(:out, :err, :logger, :tmpdir)
|
4
5
|
|
5
6
|
def initialize( out = STDOUT, err = STDERR, logger = nil , tmpdir = '/tmp/fpm-fry' )
|
6
|
-
logger ||=
|
7
|
+
logger ||= Channel.new.tap{|chan| chan.subscribe(Cabin::NiceOutput.new(out)) }
|
7
8
|
FileUtils.mkdir_p( tmpdir )
|
8
9
|
super( out, err, logger, tmpdir )
|
9
10
|
end
|
data/lib/fpm/package/docker.rb
CHANGED
@@ -25,7 +25,7 @@ class FPM::Package::Docker < FPM::Package
|
|
25
25
|
def split( name, map )
|
26
26
|
changes = changes(name)
|
27
27
|
changes.remove_modified_leaves! do | ml |
|
28
|
-
@logger.warn("Found a modified file. You can only create new files in a package",
|
28
|
+
@logger.warn("Found a modified file. You can only create new files in a package",name: ml)
|
29
29
|
end
|
30
30
|
fmap = {}
|
31
31
|
changes.leaves.each do | change |
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fpm-fry
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hannes Georg
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-12-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: excon
|
@@ -49,6 +49,7 @@ files:
|
|
49
49
|
- lib/cabin/nice_output.rb
|
50
50
|
- lib/fpm/fry/block_enumerator.rb
|
51
51
|
- lib/fpm/fry/build_output_parser.rb
|
52
|
+
- lib/fpm/fry/channel.rb
|
52
53
|
- lib/fpm/fry/client.rb
|
53
54
|
- lib/fpm/fry/command.rb
|
54
55
|
- lib/fpm/fry/command/cook.rb
|
@@ -58,12 +59,15 @@ files:
|
|
58
59
|
- lib/fpm/fry/os_db.rb
|
59
60
|
- lib/fpm/fry/plugin.rb
|
60
61
|
- lib/fpm/fry/plugin/alternatives.rb
|
62
|
+
- lib/fpm/fry/plugin/config.rb
|
61
63
|
- lib/fpm/fry/plugin/edit_staging.rb
|
62
64
|
- lib/fpm/fry/plugin/exclude.rb
|
63
65
|
- lib/fpm/fry/plugin/init.rb
|
64
66
|
- lib/fpm/fry/plugin/platforms.rb
|
67
|
+
- lib/fpm/fry/plugin/same_version.rb
|
65
68
|
- lib/fpm/fry/plugin/script_helper.rb
|
66
69
|
- lib/fpm/fry/plugin/service.rb
|
70
|
+
- lib/fpm/fry/plugin/user.rb
|
67
71
|
- lib/fpm/fry/recipe.rb
|
68
72
|
- lib/fpm/fry/recipe/builder.rb
|
69
73
|
- lib/fpm/fry/source.rb
|
@@ -103,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
107
|
version: '0'
|
104
108
|
requirements: []
|
105
109
|
rubyforge_project:
|
106
|
-
rubygems_version: 2.
|
110
|
+
rubygems_version: 2.4.8
|
107
111
|
signing_key:
|
108
112
|
specification_version: 4
|
109
113
|
summary: FPM Fry
|