fpm-fry 0.2.2 → 0.4.6
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/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
|