fpm-fry 0.2.2 → 0.4.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/lib/cabin/nice_output.rb +16 -1
- data/lib/fpm/fry/block_enumerator.rb +6 -3
- data/lib/fpm/fry/build_output_parser.rb +10 -5
- data/lib/fpm/fry/channel.rb +13 -0
- data/lib/fpm/fry/chroot.rb +2 -2
- data/lib/fpm/fry/client.rb +96 -12
- data/lib/fpm/fry/command.rb +15 -32
- data/lib/fpm/fry/command/cook.rb +38 -56
- data/lib/fpm/fry/detector.rb +43 -98
- data/lib/fpm/fry/docker_file.rb +60 -26
- data/lib/fpm/fry/exec.rb +76 -0
- data/lib/fpm/fry/inspector.rb +70 -0
- data/lib/fpm/fry/joined_io.rb +1 -1
- data/lib/fpm/fry/plugin/apt.rb +52 -0
- data/lib/fpm/fry/plugin/edit_staging.rb +1 -1
- data/lib/fpm/fry/plugin/env.rb +45 -0
- data/lib/fpm/fry/plugin/init.rb +71 -42
- data/lib/fpm/fry/plugin/service.rb +108 -49
- data/lib/fpm/fry/plugin/systemd.rb +75 -0
- data/lib/fpm/fry/recipe.rb +64 -23
- data/lib/fpm/fry/recipe/builder.rb +53 -20
- data/lib/fpm/fry/source.rb +41 -12
- data/lib/fpm/fry/source/{package.rb → archive.rb} +115 -35
- data/lib/fpm/fry/source/dir.rb +13 -8
- data/lib/fpm/fry/source/git.rb +81 -45
- data/lib/fpm/fry/source/patched.rb +61 -32
- data/lib/fpm/fry/tar.rb +63 -0
- data/lib/fpm/fry/templates/debian/after_remove.erb +1 -1
- data/lib/fpm/fry/templates/debian/before_remove.erb +1 -1
- data/lib/fpm/fry/ui.rb +1 -1
- data/lib/fpm/fry/with_data.rb +34 -0
- data/lib/fpm/package/docker.rb +16 -0
- metadata +82 -13
- data/lib/fpm/fry/os_db.rb +0 -36
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'fpm/fry/plugin'
|
2
|
+
require 'fpm/fry/chroot'
|
3
|
+
|
4
|
+
# Automatically adds the appropriate maintainer scripts for every systemd unit.
|
5
|
+
#
|
6
|
+
# @note experimental
|
7
|
+
#
|
8
|
+
# @example in a recipe
|
9
|
+
# plugin 'systemd' # no options required, just install your units in /lib/systemd/system
|
10
|
+
module FPM::Fry::Plugin::Systemd
|
11
|
+
|
12
|
+
# @api private
|
13
|
+
VALID_UNITS = /\A[a-z_0-9\-]+@?\.(service|socket|timer)\z/
|
14
|
+
|
15
|
+
# @api private
|
16
|
+
INSTANTIATED_UNITS = /\A[a-z_0-9\-]+@\.(service|socket|timer)\z/
|
17
|
+
|
18
|
+
# @api private
|
19
|
+
class Callback < Struct.new(:script_helper)
|
20
|
+
|
21
|
+
def call(_, package)
|
22
|
+
chroot = FPM::Fry::Chroot.new(package.staging_path)
|
23
|
+
files = chroot.entries('lib/systemd/system') - ['.','..']
|
24
|
+
valid, invalid = files.partition{|file| VALID_UNITS =~ file }
|
25
|
+
if invalid.any?
|
26
|
+
package.logger.warning("Found #{invalid.size} files in systemd unit path that are no systemd units", files: invalid)
|
27
|
+
end
|
28
|
+
units = valid.grep_v(INSTANTIATED_UNITS)
|
29
|
+
return if units.none?
|
30
|
+
package.logger.info("Added #{units.size} systemd units", units: valid)
|
31
|
+
script_helper.after_install_or_upgrade install(units)
|
32
|
+
script_helper.before_remove_entirely before_remove(units)
|
33
|
+
script_helper.after_remove_entirely after_remove(units)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def install(units)
|
38
|
+
<<BASH
|
39
|
+
if systemctl is-system-running ; then
|
40
|
+
systemctl preset #{units.join(' ')}
|
41
|
+
if systemctl is-enabled #{units.join(' ')} ; then
|
42
|
+
systemctl daemon-reload
|
43
|
+
systemctl restart #{units.join(' ')}
|
44
|
+
fi
|
45
|
+
fi
|
46
|
+
BASH
|
47
|
+
end
|
48
|
+
|
49
|
+
def before_remove(units)
|
50
|
+
<<BASH
|
51
|
+
if systemctl is-system-running ; then
|
52
|
+
systemctl disable --now #{units.join(' ')}
|
53
|
+
fi
|
54
|
+
BASH
|
55
|
+
end
|
56
|
+
|
57
|
+
def after_remove(units)
|
58
|
+
<<BASH
|
59
|
+
if systemctl is-system-running ; then
|
60
|
+
systemctl daemon-reload
|
61
|
+
systemctl reset-failed #{units.join(' ')}
|
62
|
+
fi
|
63
|
+
BASH
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.apply(builder)
|
69
|
+
return unless builder.plugin('init').systemd?
|
70
|
+
builder.plugin('script_helper') do |sh|
|
71
|
+
builder.output_hooks << Callback.new(sh)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
data/lib/fpm/fry/recipe.rb
CHANGED
@@ -1,26 +1,28 @@
|
|
1
1
|
require 'fpm/fry/source'
|
2
|
-
require 'fpm/fry/source/
|
2
|
+
require 'fpm/fry/source/archive'
|
3
3
|
require 'fpm/fry/source/dir'
|
4
4
|
require 'fpm/fry/source/patched'
|
5
5
|
require 'fpm/fry/source/git'
|
6
6
|
require 'fpm/fry/plugin'
|
7
|
-
require 'fpm/fry/
|
7
|
+
require 'fpm/fry/exec'
|
8
8
|
require 'shellwords'
|
9
9
|
require 'cabin'
|
10
|
-
require 'open3'
|
11
10
|
module FPM; module Fry
|
12
11
|
|
12
|
+
# A FPM::Fry::Recipe contains all information needed to build a package.
|
13
|
+
#
|
14
|
+
# It is usually created by {FPM::Fry::Recipe::Builder}.
|
13
15
|
class Recipe
|
14
16
|
|
17
|
+
# A FPM::Fry::Recipe::Step is a named build step.
|
18
|
+
#
|
19
|
+
# @see FPM::Fry::Recipe#steps
|
15
20
|
class Step < Struct.new(:name, :value)
|
16
21
|
def to_s
|
17
22
|
value.to_s
|
18
23
|
end
|
19
24
|
end
|
20
25
|
|
21
|
-
class DuplicateDependency < ArgumentError
|
22
|
-
end
|
23
|
-
|
24
26
|
class PackageRecipe
|
25
27
|
attr_accessor :name,
|
26
28
|
:iteration,
|
@@ -60,7 +62,12 @@ module FPM; module Fry
|
|
60
62
|
|
61
63
|
alias dependencies depends
|
62
64
|
|
65
|
+
# Applies settings to output package
|
66
|
+
# @param [FPM::Package] package
|
67
|
+
# @return [FPM::Package] package
|
68
|
+
# @api private
|
63
69
|
def apply_output( package )
|
70
|
+
output_hooks.each{|h| h.call(self, package) }
|
64
71
|
package.name = name
|
65
72
|
package.version = version
|
66
73
|
package.iteration = iteration
|
@@ -81,14 +88,16 @@ module FPM; module Fry
|
|
81
88
|
end
|
82
89
|
end
|
83
90
|
end
|
84
|
-
output_hooks.each{|h| h.call(self, package) }
|
85
91
|
return package
|
86
92
|
end
|
87
93
|
|
88
94
|
alias apply apply_output
|
89
95
|
|
96
|
+
# @api private
|
90
97
|
SYNTAX_CHECK_SHELLS = ['/bin/sh','/bin/bash', '/bin/dash']
|
91
98
|
|
99
|
+
# Lints the settings for some common problems
|
100
|
+
# @return [Array<String>] problems
|
92
101
|
def lint
|
93
102
|
problems = []
|
94
103
|
problems << "Name is empty." if name.to_s == ''
|
@@ -110,41 +119,58 @@ module FPM; module Fry
|
|
110
119
|
problems << "#{type} script doesn't have a valid command in shebang"
|
111
120
|
end
|
112
121
|
if SYNTAX_CHECK_SHELLS.include? args[0]
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
problems << "#{type} script is not valid #{args[0]} code: #{serr.read.chomp}"
|
122
|
+
begin
|
123
|
+
Exec::exec(args[0],'-n', stdin_data: s)
|
124
|
+
rescue Exec::Failed => e
|
125
|
+
problems << "#{type} script is not valid #{args[0]} code: #{e.stderr.chomp}"
|
118
126
|
end
|
119
|
-
serr.close
|
120
|
-
sout.close
|
121
127
|
end
|
122
128
|
end
|
123
129
|
return problems
|
124
130
|
end
|
125
131
|
end
|
126
132
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
133
|
+
# @return [FPM::Fry::Source] the source used for building
|
134
|
+
attr_accessor :source
|
135
|
+
|
136
|
+
attr_accessor :build_mounts
|
137
|
+
|
138
|
+
# @return [Array<#to_s>] steps that will be carried out before dependencies are installed
|
139
|
+
attr_accessor :before_dependencies_steps
|
140
|
+
|
141
|
+
# @return [Array<#to_s>] steps that will be carried out before build
|
142
|
+
attr_accessor :before_build_steps
|
143
|
+
|
144
|
+
# @return [Array<#to_s>] steps that will be carried out during build
|
145
|
+
attr_accessor :steps
|
146
|
+
|
147
|
+
# @return [Array<FPM::Fry::PackageRecipe>] a list of packages that will be created
|
148
|
+
attr_accessor :packages
|
149
|
+
|
150
|
+
# @return [Hash<String,Hash>] build dependencies
|
151
|
+
attr_accessor :build_depends
|
152
|
+
|
153
|
+
# @return [Array<#call>] hooks that will be called on the input package
|
154
|
+
attr_accessor :input_hooks
|
155
|
+
|
156
|
+
# @return [Array<#call>] hooks that will be called when building the Dockerfile
|
157
|
+
attr_accessor :dockerfile_hooks
|
135
158
|
|
136
159
|
def initialize
|
137
160
|
@source = Source::Null
|
161
|
+
@before_dependencies_steps = []
|
138
162
|
@before_build_steps = []
|
139
163
|
@steps = []
|
140
164
|
@packages = [PackageRecipe.new]
|
141
165
|
@packages[0].files << '**'
|
142
166
|
@build_depends = {}
|
143
167
|
@input_hooks = []
|
168
|
+
@dockerfile_hooks = []
|
144
169
|
@build_mounts = []
|
145
|
-
@apt_setup = []
|
146
170
|
end
|
147
171
|
|
172
|
+
# Calculates all dependencies of this recipe
|
173
|
+
# @return [Hash<String,Hash>] the dependencies
|
148
174
|
def depends
|
149
175
|
depends = @packages.map(&:depends).inject(:merge)
|
150
176
|
@packages.map(&:name).each do | n |
|
@@ -153,15 +179,30 @@ module FPM; module Fry
|
|
153
179
|
return depends
|
154
180
|
end
|
155
181
|
|
182
|
+
# Checks all packages for common errors
|
183
|
+
# @return [Array<String>] problems
|
156
184
|
def lint
|
157
185
|
packages.flat_map(&:lint)
|
158
186
|
end
|
159
187
|
|
188
|
+
# Applies input settings to package
|
189
|
+
# @param [FPM::Package] package
|
190
|
+
# @return [FPM::Package]
|
160
191
|
def apply_input( package )
|
161
192
|
input_hooks.each{|h| h.call(self, package) }
|
162
193
|
return package
|
163
194
|
end
|
164
195
|
|
196
|
+
# Filters the dockerfile
|
197
|
+
# @api experimental
|
198
|
+
# @param [Hash] df
|
199
|
+
def apply_dockerfile_hooks( df )
|
200
|
+
dockerfile_hooks.each do |hook|
|
201
|
+
hook.call(self, df)
|
202
|
+
end
|
203
|
+
return nil
|
204
|
+
end
|
205
|
+
|
165
206
|
end
|
166
207
|
|
167
208
|
end ; end
|
@@ -1,21 +1,38 @@
|
|
1
1
|
require 'fpm/fry/recipe'
|
2
2
|
require 'fpm/fry/recipe/error'
|
3
3
|
require 'forwardable'
|
4
|
+
require 'fpm/fry/channel'
|
5
|
+
|
4
6
|
module FPM::Fry
|
5
7
|
class Recipe
|
6
8
|
|
7
9
|
class NotFound < StandardError
|
8
10
|
end
|
9
11
|
|
10
|
-
class PackageBuilder
|
12
|
+
class PackageBuilder
|
13
|
+
|
14
|
+
# @return [Hash<Symbol,Object>]
|
15
|
+
attr :variables
|
16
|
+
|
17
|
+
# @return [FPM::Fry::PackageRecipe]
|
18
|
+
attr :package_recipe
|
11
19
|
|
20
|
+
# @return [Cabin::Channel]
|
12
21
|
attr :logger
|
13
22
|
|
14
|
-
|
15
|
-
|
23
|
+
# @return [FPM::Fry::Inspector,nil]
|
24
|
+
attr :inspector
|
25
|
+
|
26
|
+
# @api private
|
27
|
+
def initialize( variables, package_recipe, options = {})
|
28
|
+
@variables = variables
|
29
|
+
@package_recipe = package_recipe
|
16
30
|
@logger = options.fetch(:logger){ Cabin::Channel.get }
|
31
|
+
@inspector = options[:inspector]
|
17
32
|
end
|
18
33
|
|
34
|
+
# Returns the package type ( e.g. "debian" or "redhat" ).
|
35
|
+
# @return [String]
|
19
36
|
def flavour
|
20
37
|
variables[:flavour]
|
21
38
|
end
|
@@ -25,9 +42,13 @@ module FPM::Fry
|
|
25
42
|
end
|
26
43
|
alias platform distribution
|
27
44
|
|
28
|
-
|
29
|
-
|
45
|
+
# The release version of the distribution ( e.g. "12.04" or "6.0.7" )
|
46
|
+
# @return [String]
|
47
|
+
def release
|
48
|
+
variables[:release]
|
30
49
|
end
|
50
|
+
|
51
|
+
alias distribution_version release
|
31
52
|
alias platform_version distribution_version
|
32
53
|
|
33
54
|
def codename
|
@@ -174,20 +195,20 @@ module FPM::Fry
|
|
174
195
|
|
175
196
|
class Builder < PackageBuilder
|
176
197
|
|
198
|
+
# @return [FPM::Fry::Recipe]
|
177
199
|
attr :recipe
|
178
200
|
|
179
|
-
|
201
|
+
# @param [Hash<Symbol,Object>] variables
|
202
|
+
# @param [Hash] options
|
203
|
+
# @option options [FPM::Fry::Recipe] :recipe (Recipe.new)
|
204
|
+
# @option options [Cabin::Channel] :logger (default cabin channel)
|
205
|
+
# @option options [FPM::Fry::Inspector] :inspector
|
206
|
+
def initialize( variables, options = {} )
|
207
|
+
recipe = options.fetch(:recipe){ Recipe.new }
|
180
208
|
variables = variables.dup
|
181
|
-
if variables[:distribution] && !variables[:flavour] && OsDb[variables[:distribution]]
|
182
|
-
variables[:flavour] = OsDb[variables[:distribution]][:flavour]
|
183
|
-
end
|
184
|
-
if !variables[:codename] && OsDb[variables[:distribution]] && variables[:distribution_version]
|
185
|
-
codename = OsDb[variables[:distribution]][:codenames].find{|name,version| variables[:distribution_version].start_with? version }
|
186
|
-
variables[:codename] = codename[0] if codename
|
187
|
-
end
|
188
209
|
variables.freeze
|
189
210
|
@recipe = recipe
|
190
|
-
@
|
211
|
+
@steps = :steps
|
191
212
|
register_default_source_types!
|
192
213
|
super(variables, recipe.packages[0], options)
|
193
214
|
end
|
@@ -218,7 +239,9 @@ module FPM::Fry
|
|
218
239
|
end
|
219
240
|
|
220
241
|
def apt_setup(cmd)
|
221
|
-
|
242
|
+
before_dependencies do
|
243
|
+
bash cmd
|
244
|
+
end
|
222
245
|
end
|
223
246
|
|
224
247
|
def run(*args)
|
@@ -237,7 +260,10 @@ module FPM::Fry
|
|
237
260
|
code = Recipe::Step.new(name, code)
|
238
261
|
end
|
239
262
|
# Don't do this at home
|
240
|
-
|
263
|
+
case(@steps)
|
264
|
+
when :before_dependencies
|
265
|
+
recipe.before_dependencies_steps << code
|
266
|
+
when :before_build
|
241
267
|
recipe.before_build_steps << code
|
242
268
|
else
|
243
269
|
recipe.steps << code
|
@@ -245,10 +271,17 @@ module FPM::Fry
|
|
245
271
|
end
|
246
272
|
|
247
273
|
def before_build
|
248
|
-
@
|
274
|
+
steps, @steps = @steps, :before_build
|
275
|
+
yield
|
276
|
+
ensure
|
277
|
+
@steps = steps
|
278
|
+
end
|
279
|
+
|
280
|
+
def before_dependencies
|
281
|
+
steps, @steps = @steps, :before_dependencies
|
249
282
|
yield
|
250
283
|
ensure
|
251
|
-
@
|
284
|
+
@steps = steps
|
252
285
|
end
|
253
286
|
|
254
287
|
def build_depends( name , options = {} )
|
@@ -266,7 +299,7 @@ module FPM::Fry
|
|
266
299
|
pr.version = package_recipe.version
|
267
300
|
pr.iteration = package_recipe.iteration
|
268
301
|
recipe.packages << pr
|
269
|
-
PackageBuilder.new(variables, pr).instance_eval(&block)
|
302
|
+
PackageBuilder.new(variables, pr, logger: logger, inspector: inspector).instance_eval(&block)
|
270
303
|
end
|
271
304
|
|
272
305
|
protected
|
@@ -289,7 +322,7 @@ module FPM::Fry
|
|
289
322
|
|
290
323
|
def register_default_source_types!
|
291
324
|
register_source_type Source::Git
|
292
|
-
register_source_type Source::
|
325
|
+
register_source_type Source::Archive
|
293
326
|
register_source_type Source::Dir
|
294
327
|
end
|
295
328
|
|
data/lib/fpm/fry/source.rb
CHANGED
@@ -1,34 +1,40 @@
|
|
1
|
+
require 'fpm/fry/with_data'
|
1
2
|
module FPM; module Fry ; module Source
|
2
3
|
|
4
|
+
# Raised when building a cache failed.
|
3
5
|
class CacheFailed < StandardError
|
4
|
-
|
5
|
-
attr :data
|
6
|
-
|
7
|
-
def initialize(e, data = {})
|
8
|
-
if e.kind_of? Exception
|
9
|
-
@data = {reason: e}.merge data
|
10
|
-
super(e.message)
|
11
|
-
else
|
12
|
-
@data = data.dup
|
13
|
-
super(e.to_s)
|
14
|
-
end
|
15
|
-
end
|
6
|
+
include WithData
|
16
7
|
end
|
17
8
|
|
9
|
+
# A special source that is empty.
|
18
10
|
module Null
|
19
11
|
|
12
|
+
# A special cache that is empty.
|
20
13
|
module Cache
|
14
|
+
|
15
|
+
# @return [IO] an empty tar
|
21
16
|
def self.tar_io
|
22
17
|
StringIO.new("\x00"*1024)
|
23
18
|
end
|
19
|
+
|
20
|
+
# @return [Hash] an empty hash
|
24
21
|
def self.file_map
|
25
22
|
return {}
|
26
23
|
end
|
24
|
+
|
25
|
+
# @return [String] 32 times zero
|
27
26
|
def self.cachekey
|
28
27
|
return '0' * 32
|
29
28
|
end
|
29
|
+
|
30
|
+
# @return [String] common path prefix of all files that should be stripped
|
31
|
+
def self.prefix
|
32
|
+
return ""
|
33
|
+
end
|
30
34
|
end
|
31
35
|
|
36
|
+
# @see FPM::Fry::Source::Null::Cache
|
37
|
+
# @return {FPM::Fry::Source::Null::Cache}
|
32
38
|
def self.build_cache(*_)
|
33
39
|
return Cache
|
34
40
|
end
|
@@ -37,11 +43,34 @@ module FPM; module Fry ; module Source
|
|
37
43
|
|
38
44
|
class << self
|
39
45
|
|
46
|
+
# @api private
|
40
47
|
def guess_regex(rx, url)
|
41
48
|
if m = rx.match(url.to_s)
|
42
49
|
return m[0].size
|
43
50
|
end
|
44
51
|
end
|
45
52
|
|
53
|
+
# @api private
|
54
|
+
# @param dir [String] directory
|
55
|
+
# @return [String] prefix
|
56
|
+
def prefix(dir)
|
57
|
+
e = ::Dir.entries(dir)
|
58
|
+
if e.size != 3
|
59
|
+
return ""
|
60
|
+
end
|
61
|
+
other = (e - ['.','..']).first
|
62
|
+
path = File.join(dir, other)
|
63
|
+
if File.directory?( path )
|
64
|
+
pf = prefix(path)
|
65
|
+
if pf == ""
|
66
|
+
return other
|
67
|
+
else
|
68
|
+
return File.join(other, pf)
|
69
|
+
end
|
70
|
+
else
|
71
|
+
return ""
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
46
75
|
end
|
47
76
|
end ; end ; end
|